it-swarm-es.tech

¿Cómo puedes ver el enlace duro real por ls?

Corro

ln /a/A /b/B

Me gustaría ver en la carpeta a donde apunta el archivo A por ls.

Puede encontrar el número de inodo para su archivo con

ls -i

y

ls -l

muestra el recuento de referencias (número de enlaces físicos a un inodo particular)

después de encontrar el número de inodo, puede buscar todos los archivos con el mismo inodo:

find . -inum NUM

mostrará los nombres de archivo para el inodo NUM en el directorio actual (.)

163
zzr

Realmente no hay una respuesta bien definida para tu pregunta. A diferencia de los enlaces simbólicos, los enlaces físicos son indistinguibles del "archivo original".

Las entradas de directorio constan de un nombre de archivo y un puntero a un inodo. El inodo, a su vez, contiene los metadatos del archivo y (punteros a) el contenido real del archivo). Crear un enlace duro crea otro nombre de archivo + referencia al mismo inodo. Estas referencias son unidireccionales (al menos en sistemas de archivos típicos): el inodo solo mantiene un recuento de referencias. No hay una forma intrínseca de averiguar cuál es el nombre de archivo "original".

Por cierto, esta es la razón por la que la llamada del sistema para "eliminar" un archivo se llama unlink. Simplemente elimina un enlace duro. El inodo y los datos adjuntos se eliminan solo si el recuento de referencia del inodo se reduce a 0.

La única forma de encontrar las otras referencias a un inodo dado es buscar exhaustivamente en el sistema de archivos, verificando qué archivos se refieren al inodo en cuestión. Puede usar 'probar A -ef B' desde el Shell para realizar esta comprobación.

60
Laurence Gonsalves

UNIX tiene enlaces duros y enlaces simbólicos (hechos con "ln" y "ln -s" respectivamente). Los enlaces simbólicos son simplemente un archivo que contiene la ruta real a otro archivo y puede cruzar sistemas de archivos.

Los enlaces duros han existido desde los primeros días de UNIX (que puedo recordar de todos modos, y eso se remonta bastante tiempo). Son dos entradas de directorio que hacen referencia a los mismos datos subyacentes exactos . Los datos en un archivo se especifican por su inode. Cada archivo en un sistema de archivos apunta a un inodo, pero no hay ningún requisito de que cada archivo apunte a un inodo único, de ahí provienen los enlaces duros.

Dado que los inodos son únicos solo para un sistema de archivos dado, existe una limitación de que los enlaces duros deben estar en el mismo sistema de archivos (a diferencia de los enlaces simbólicos). Tenga en cuenta que, a diferencia de los enlaces simbólicos, no hay un archivo con privilegios, todos son iguales. El área de datos solo se publicará cuando todos se eliminen los archivos que usan ese inodo (y todos los procesos también lo cierran, pero eso es un problema diferente).

Puede usar el comando "ls -i" para obtener el inodo de un archivo en particular. Luego puede usar el comando "find <filesystemroot> -inum <inode>" para encontrar todos los archivos en el sistema de archivos con ese inodo dado.

Aquí hay un guión que hace exactamente eso. Lo invocas con:

findhardlinks ~/jquery.js

y encontrará todos los archivos en ese sistema de archivos que son enlaces duros para ese archivo:

[email protected]:~# ./findhardlinks /home/pax/jquery.js
Processing '/home/pax/jquery.js'
   '/home/pax/jquery.js' has inode 5211995 on mount point '/'
       /home/common/jquery-1.2.6.min.js
       /home/pax/jquery.js

Aquí está el guión.

#!/bin/bash
if [[ $# -lt 1 ]] ; then
    echo "Usage: findhardlinks <fileOrDirToFindFor> ..."
    exit 1
fi

while [[ $# -ge 1 ]] ; do
    echo "Processing '$1'"
    if [[ ! -r "$1" ]] ; then
        echo "   '$1' is not accessible"
    else
        numlinks=$(ls -ld "$1" | awk '{print $2}')
        inode=$(ls -id "$1" | awk '{print $1}' | head -1l)
        device=$(df "$1" | tail -1l | awk '{print $6}')
        echo "   '$1' has inode ${inode} on mount point '${device}'"
        find ${device} -inum ${inode} 2>/dev/null | sed 's/^/        /'
    fi
    shift
done
33
user53528
ls -l

La primera columna representará los permisos. La segunda columna será el número de subelementos (para directorios) o el número de rutas a los mismos datos (enlaces físicos, incluido el archivo original) al archivo. P.ej:

[email protected]    2    [username]    [group]    [timestamp]     HardLink
[email protected]    2    [username]    [group]    [timestamp]     Original
               ^ Number of hard links to the data
24
eyelidlessness

¿Qué tal el siguiente más simple? (¡Este último podría reemplazar los scripts largos de arriba!)

Si tiene un archivo específico <THEFILENAME> y desea conocer todos sus enlaces físicos distribuidos en el directorio <TARGETDIR>, (que puede ser todo el sistema de archivos indicado por /)

find <TARGETDIR> -type f -samefile  <THEFILENAME>

Ampliación de la lógica, si desea conocer todos los archivos en el <SOURCEDIR> con múltiples enlaces duros repartidos en <TARGETDIR>:

find <SOURCEDIR> -type f -links +1   \
  -printf "\n\n %n HardLinks of file : %H/%f  \n"   \
  -exec find <TARGETDIR> -type f -samefile {} \; 
11
Loves Probability

Hay muchas respuestas con scripts para encontrar todos los enlaces duros en un sistema de archivos. La mayoría de ellos hacen cosas tontas como correr, buscar y escanear todo el sistema de archivos en busca de -samefile para CADA archivo con múltiples enlaces. Esto es Loco; Todo lo que necesita es ordenar el número de inodo e imprimir duplicados.

find directories.. -xdev ! -type d -links +1 -printf '%20D %20i %p\n' | sort -n | uniq -w 42 --all-repeated=separate (Gracias a @Tino por ajustar mi comando original para que sea compatible con un FS-id (%D), y para manejar todos los tipos de archivos que no sean de directorio, no solo los archivos normales. Encontraremos enlaces simbólicos con enlaces múltiples, canalizaciones, etc.)

Usar ! -type d -links +1 significa que la entrada de la clasificación es tan grande como la salida final de uniq. A menos que lo ejecute en un subdirectorio que solo contenga uno de un conjunto de enlaces físicos. De todos modos, esto usará MUCHO menos tiempo de CPU para volver a atravesar el sistema de archivos que cualquier otra solución publicada.

salida de muestra:

...
            2429             76732484 /home/peter/weird-filenames/test/.hiddendir/foo bar
            2429             76732484 /home/peter/weird-filenames/test.orig/.hiddendir/foo bar

            2430             17961006 /usr/bin/pkg-config.real
            2430             17961006 /usr/bin/x86_64-pc-linux-gnu-pkg-config

            2430             36646920 /usr/lib/i386-linux-gnu/dri/i915_dri.so
            2430             36646920 /usr/lib/i386-linux-gnu/dri/i965_dri.so
            2430             36646920 /usr/lib/i386-linux-gnu/dri/nouveau_vieux_dri.so
            2430             36646920 /usr/lib/i386-linux-gnu/dri/r200_dri.so
            2430             36646920 /usr/lib/i386-linux-gnu/dri/radeon_dri.so
...

TODO ?: Descomprimir la salida. uniq tiene un soporte de selección de campo muy limitado, así que relleno la salida de búsqueda y uso ancho fijo. 20chars es lo suficientemente ancho para el número máximo de inode o dispositivo posible (2 ^ 64-1 = 18446744073709551615). XFS elige los números de inodo según el lugar en el que se asignan los discos, no de forma contigua a 0, por lo que los sistemas de archivos XFS grandes pueden tener números de inodo de 32 bits, incluso si no tienen miles de millones de archivos. Otros sistemas de archivos pueden tener números de inodo de 20 dígitos incluso si no son gigantescos.

TODO: ordenar grupos de duplicados por ruta. Tenerlos ordenados por punto de montaje, luego el número de inodo mezcla las cosas, si tiene un par de subdirectorios diferentes que tienen muchos enlaces físicos. (Es decir, los grupos de dup-grupos van juntos, pero la salida los mezcla).

Un sort -k 3 final ordenaría las líneas por separado, no los grupos de líneas como un solo registro. El preprocesamiento con algo para transformar un par de nuevas líneas en un byte NUL, y el uso de GNU sort --zero-terminated -k 3 puede hacer el truco. Sin embargo, tr solo funciona con caracteres individuales, no con 2> 1 o 1> 2 patrones. Perl lo haría (o simplemente analizar y clasificar dentro de Perl o awk). sed también podría funcionar.

4
Peter Cordes

Esto es algo así como un comentario a la propia respuesta y guión de Torocoro-Macho, pero obviamente no cabe en el cuadro de comentarios.


Reescriba su secuencia de comandos con formas más sencillas de encontrar la información y, por lo tanto, con muchas menos invocaciones de procesos.

#!/bin/sh
xPATH=$(readlink -f -- "${1}")
for xFILE in "${xPATH}"/*; do
    [ -d "${xFILE}" ] && continue
    [ ! -r "${xFILE}" ] && printf '"%s" is not readable.\n' "${xFILE}" 1>&2 && continue
    nLINKS=$(stat -c%h "${xFILE}")
    if [ ${nLINKS} -gt 1 ]; then
        iNODE=$(stat -c%i "${xFILE}")
        xDEVICE=$(stat -c%m "${xFILE}")
        printf '\nItem: %s[%d] = %s\n' "${xDEVICE}" "${iNODE}" "${xFILE}";
        find "${xDEVICE}" -inum ${iNODE} -not -path "${xFILE}" -printf '     -> %p\n' 2>/dev/null
    fi
done

Intenté mantenerlo lo más parecido posible al tuyo para facilitar la comparación.

Comentarios sobre este script y el tuyo.

  • Uno siempre debe evitar el código $IFS si un globo es suficiente, ya que es innecesariamente complicado, y los nombres de los archivos pueden contener nuevas líneas (pero en la práctica, principalmente la primera razón).

  • Debe evitar analizar manualmente ls y obtener la mayor cantidad de resultados posible, ya que tarde o temprano lo morderá. Por ejemplo: en su primera línea awk, falla en todos los nombres de archivos que contienen espacios.

  • printf a menudo evitará problemas al final, ya que es tan robusto con la sintaxis %s. También le da control total sobre la salida, y es consistente en todos los sistemas , a diferencia de echo.

  • stat puede ahorrarle mucha lógica en este caso.

  • GNU find es poderoso.

  • Sus invocaciones head y tail podrían haberse manejado directamente en awk con, por ejemplo. el comando exit y/o la selección en la variable NR. Esto ahorraría las invocaciones de procesos, que casi siempre mejoran el rendimiento en los scripts de trabajo duro.

  • Su egreps podría ser simplemente grep.

3
Daniel Andersson

Basado en el script findhardlinks (lo renombré a hard-links), esto es lo que he refactorizado y hecho que funcione.

Salida:

# ./hard-links /root

Item: /[10145] = /root/.profile
    -> /proc/907/sched
    -> /<some-where>/.profile

Item: /[10144] = /root/.tested
    -> /proc/907/limits
    -> /<some-where else>/.bashrc
    -> /root/.testlnk

Item: /[10144] = /root/.testlnk
    -> /proc/907/limits
    -> /<another-place else>/.bashrc
    -> /root/.tested

# cat ./hard-links
#!/bin/bash
oIFS="${IFS}"; IFS=$'\n';
xPATH="${1}";
xFILES="`ls -al ${xPATH}|egrep "^-"|awk '{print $9}'`";
for xFILE in ${xFILES[@]}; do
  xITEM="${xPATH}/${xFILE}";
  if [[ ! -r "${xITEM}" ]] ; then
    echo "Path: '${xITEM}' is not accessible! ";
  else
    nLINKS=$(ls -ld "${xITEM}" | awk '{print $2}')
    if [ ${nLINKS} -gt 1 ]; then
      iNODE=$(ls -id "${xITEM}" | awk '{print $1}' | head -1l)
      xDEVICE=$(df "${xITEM}" | tail -1l | awk '{print $6}')
      echo -e "\nItem: ${xDEVICE}[$iNODE] = ${xITEM}";
      find ${xDEVICE} -inum ${iNODE} 2>/dev/null|egrep -v "${xITEM}"|sed 's/^/   -> /';
    fi
  fi
done
IFS="${oIFS}"; echo "";
2
Torocoro-Macho

Una solución GUI se acerca mucho a tu pregunta:

No puede enumerar los archivos reales vinculados de "ls" porque, como han señalado los comentaristas anteriores, los "nombres" del archivo son meros alias para los mismos datos. Sin embargo, en realidad hay una herramienta GUI que se acerca mucho a lo que usted quiere, que es mostrar una lista de rutas de nombres de archivos que apuntan a los mismos datos (como enlaces duros) bajo Linux, se llama FSLint. La opción que desea está en "Choques de nombres" -> deseleccione "casilla $ PATH" en Buscar (XX) -> y seleccione "Alias" en el cuadro desplegable después de "para ..." hacia la parte superior central.

FSLint está muy mal documentado, pero encontré eso asegurándome de que el árbol de directorios limitado en "Ruta de búsqueda" con la casilla de verificación seleccionada para "¿Repetir?" y las opciones antes mencionadas, una lista de datos enlazados con rutas y nombres que "apuntan" a los mismos datos se producen después de que el programa busca.

1
Charles

Puede configurar ls para resaltar los enlaces físicos usando un 'alias', pero como se indicó anteriormente, no hay manera de mostrar la 'fuente' del enlace duro, por eso le agrego .hardlink para ayudar con eso.

highlight hardlinks

Agrega lo siguiente en algún lugar de tu .bashrc

alias ll='LC_COLLATE=C LS_COLORS="$LS_COLORS:mh=1;37" ls -lA --si --group-directories-first'
1