¿Hay dos archivos vinculados?

27

¿Cómo puedo saber si dos archivos están vinculados desde la línea de comandos? Por ejemplo, algo vincula esto:

$ ls
fileA fileB fileC

$ is-hardlinked fileA fileB
yes

$ is-hardlinked fileA fileC
no
Vincent Scheib
fuente

Respuestas:

37

En la mayoría de los sistemas de archivos¹, un archivo está determinado únicamente por su número de inodo , por lo que todo lo que necesita verificar es si los dos archivos tienen el mismo número de inodo y si están en el mismo sistema de archivos.

Ash, ksh, bash y zsh tienen una construcción que hace la comprobación por ti: el operador de igualdad de archivos -ef.

[ fileA -ef fileB ] && ! [ fileA -ef fileC ]

Para casos más avanzados, ls -i /path/to/fileenumera el número de inodo de un archivo. df -P /path/to/filemuestra en qué sistema de archivos está el archivo (si dos archivos están en el mismo directorio, están en el mismo sistema de archivos). Si su sistema tiene el statcomando, probablemente pueda mostrar los números de inodo y del sistema de archivos ( statvaría de un sistema a otro, consulte su documentación). Si desea un vistazo rápido de los enlaces duros dentro de un directorio, intente ls -i | sort(posiblemente conectado a awk ).

¹ Todos los sistemas de archivos nativos de Unix, y algunos otros como NTFS, pero posiblemente no casos exóticos como CramFS.

Gilles 'SO- deja de ser malvado'
fuente
Y definitivamente no en nada basado en FAT, donde se detectaría como un archivo "reticulado".
Ignacio Vazquez-Abrams
44
Tenga en cuenta que fileA -ef fileBtambién devuelve 0(éxito) si fileAes un enlace simbólico a fileB, o viceversa, o ambos se vinculan al mismo archivo.
Janmoesen
¿Cómo ejecutas el comando que sugeriste? Intenté [.bashrc -ef .bash / .bashrc] y variaciones de esto, pero realmente no funcionó.
Charlie Parker
@CharlieParker [ .bashrc -ef .bash/.bashrc ]es correcto. Sin contexto, por supuesto, no tengo ni idea de por qué “no funcionó” - que podría ser la comparación de los archivos equivocados, usted podría ser no comprobar el resultado correctamente, usted podría estar usando un intérprete sin -ef, ...
Gilles 'SO- deja de ser malvado'
2
@CharlieParker El comando es en realidad [y es sinónimo de test. Pero man [o man testle dará la página de manual del comando externo, mientras que casi todos los shell tienen un comando incorporado con opciones ligeramente diferentes, por lo que debe buscarlo en el manual de su shell.
Gilles 'SO- deja de ser malvado'
4
function is-hardlinked() {
    r=yes
    [ "`stat -c '%i' $1`" != "`stat -c '%i' $2`" ] && r=no
    echo $r
}
x-way
fuente
66
Tenga en cuenta que esto puede ser un falso positivo si los dos archivos están en sistemas de archivos diferentes pero tienen el mismo inodo. También debe probar el número de dispositivo ( stat -c %d). Y si está en Linux (dado su statcomando), su shell tiene [ fileA -ef fileB ]que hacer todo esto directamente. Además, su comando se rompe gratuitamente con nombres de archivos que contienen espacios en blanco o \[?*, o comienza con -: siempre ponga comillas dobles alrededor de las suscripciones de comandos ( "$(stat -c %i -- "$1")").
Gilles 'SO- deja de ser malvado'
1
¿Por qué usaría un montón de construcciones engorrosas pero portátiles, y luego la functionpalabra clave abyectamente no portátil con un nombre de función que (debido a que contiene un guión) viola las convenciones POSIX sobre nombres permitidos?
Charles Duffy
Olvidó citar su $1y $2. También es posible que desee utilizar la $()sintaxis en lugar de las marcas de retroceso porque los corchetes dejan en claro dónde comienza el comando y dónde termina y la anidación es más simple.
josch
3

Como sugiere el primer póster, puede escribir un script basado en algo como esto en Linux:

stat -c '%i' fileA fileB fileC
Ahora no
fuente
44
Esto no es suficiente: obtendrá el mismo número para los dos archivos si están en sistemas de archivos diferentes pero tienen el mismo inodo. También debe probar el número de dispositivo ( stat -c %d). Y si está en Linux (dado su statcomando), su shell tiene [ fileA -ef fileB ]que hacer todo esto directamente.
Gilles 'SO- deja de ser malvado'
0

Con GNU find(1)versión 4.2.11 o más reciente también puede usar esto:

if [ "yes" = "$(find fileA -samefile fileB -exec echo yes \;)" ]; then
    echo yes
else
    echo no
fi

Si fileAes el mismo archivo que fileBentonces findimprimirá "sí" y la condición se vuelve verdadera.

En contraste con el uso del operador de igualdad de archivos, -efesto generará un nuevo proceso.

josch
fuente