2009-07-25 09:41:26 +0000 2009-07-25 09:41:26 +0000
104
104

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

Ejecuto

ln /a/A /b/B

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

Respuestas (9)

182
182
182
2009-07-25 10:01:32 +0000

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

ls -i

y

ls -l

muestra el conteo de referencias (número de hardlinks a un inodo en 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 archivos para el inodo NUM en la dirección actual (.)

66
66
66
2009-07-25 09:51:57 +0000

En realidad no hay una respuesta bien definida a tu pregunta. A diferencia de los enlaces simbólicos, los enlaces duros no se distinguen del “archivo original”.

Las entradas de directorio consisten en 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). La creación de un enlace duro crea otro nombre de archivo + referencia al mismo inodo. Estas referencias son unidireccionales (al menos en los sistemas de archivos típicos): el nodo sólo mantiene un recuento de referencias. No hay 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 “borrar” un archivo se llama unlink. Sólo elimina un enlace duro. El nodo y los datos adjuntos se eliminan sólo si el recuento de referencias del nodo cae a 0.

La única manera de encontrar las otras referencias a un nodo dado es buscar exhaustivamente en el sistema de archivos comprobando qué archivos hacen referencia al nodo en cuestión. Puedes utilizar ‘test A -ef B’ desde el shell para realizar esta comprobación.

24
24
24
2009-07-25 10:01:38 +0000
ls -l

La primera columna representará los permisos. La segunda columna será el número de sub-elementos (para los directorios) o el número de rutas a los mismos datos (enlaces duros, incluyendo el archivo original) al archivo. Por ejemplo:

-rw-r--r--@ 2 [username] [group] [timestamp] HardLink
-rw-r--r--@ 2 [username] [group] [timestamp] Original
               ^ Number of hard links to the data
14
14
14
2013-08-15 08:52:16 +0000

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

Si tienes un archivo específico <THEFILENAME>y quieres conocer todos sus hardlinks repartidos por el directorio <TARGETDIR>, (que incluso puede ser todo el sistema de archivos denotado por /)

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

Extendiendo la lógica, si quieres conocer todos los archivos en el <SOURCEDIR> que tienen múltiples hardlinks repartidos por <TARGETDIR>:

find <SOURCEDIR> -type f -links +1 \
  -printf "\n\n %n HardLinks of file : %H/%f \n" \
  -exec find <TARGETDIR> -type f -samefile {} \;
6
6
6
2015-04-21 19:32:47 +0000

Hay muchas respuestas con scripts para encontrar todos los hardlinks en un sistema de archivos. La mayoría de ellos hacen cosas tontas como ejecutar find para escanear todo el sistema de archivos en busca de -samefile para CADA archivo con enlaces múltiples. Esto es una locura; todo lo que necesitas es ordenar por número de inodo e imprimir los duplicados.

Con una sola pasada por el sistema de ficheros para encontrar y agrupar todos los conjuntos de ficheros hardlinked

find dirs -xdev \! -type d -links +1 -printf '%20D %20i %p\n' |
    sort -n | uniq -w 42 --all-repeated=separate

Es mucho más rápido que las otras respuestas para encontrar múltiples conjuntos de ficheros hardlinked.
find /foo -samefile /bar es excelente para un solo archivo.

  • -xdev : limitar a un sistema de archivos. No es estrictamente necesario ya que también imprimimos el FS-id a uniq en
  • ! -type d rechazamos directorios: las entradas . y .. significan que siempre están enlazados.
  • -links +1 : cuenta de enlaces estrictamente > 1
  • -printf ... imprime el FS-id, el número de inodo y la ruta. (Con relleno a anchos de columna fijos que podemos indicar a uniq.)
  • sort -n | uniq ... ordenar numéricamente y unificar en las primeras 42 columnas, separando los grupos con una línea en blanco

Usar ! -type d -links +1 significa que la entrada de sort es sólo tan grande como la salida final de uniq, así que no estamos haciendo una gran cantidad de ordenación de cadenas. A menos que lo ejecute en un subdirectorio que sólo contenga uno de un conjunto de enlaces duros. De todos modos, esto utilizará MUCHO menos tiempo de CPU recorriendo el sistema de archivos que cualquier otra solución publicada.

muestra de salida:

...
            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
...

¿TODAS?: desempacar la salida con awk o cut. uniq tiene un soporte de selección de campos muy limitado, por lo que acolcho la salida de find y uso el ancho fijo. 20 caracteres es suficiente para el máximo número posible de inodo o dispositivo (2^64-1 = 18446744073709551615). XFS elige los números de inodo basándose en el lugar del disco en el que están asignados, no de forma contigua desde 0, por lo que los grandes sistemas de archivos XFS pueden tener números de inodo de >32bit aunque no tengan miles de millones de archivos. Otros sistemas de archivos pueden tener números de inodo de 20 dígitos aunque no sean gigantescos.

TODO: ordenar los grupos de duplicados por ruta. Tenerlos ordenados por punto de montaje y luego por número de inodo mezcla las cosas, si tiene un par de subdirectorios diferentes que tienen muchos hardlinks. (es decir, los grupos de duplicados van juntos, pero la salida los mezcla).

Un último sort -k 3 ordenaría las líneas por separado, no grupos de líneas como un único registro. El preprocesamiento con algo que transforme un par de nuevas líneas en un byte NUL, y el uso de GNU sort --zero-terminated -k 3 podría servir. Sin embargo, tr sólo opera con caracteres individuales, no con patrones de 2 - 1 o 1 - 2. perl lo haría (o simplemente parsear y ordenar dentro de perl o awk). sed también podría funcionar.

3
3
3
2012-06-13 07:40:43 +0000

Esto es una especie de comentario a la propia respuesta y script de Torocoro-Macho, pero obviamente no cabe en la caja de comentarios._

  • *

Reescribí tu script con formas más sencillas de encontrar la información, y por lo tanto 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 al tuyo para facilitar la comparación.

Comentarios sobre este script y el tuyo

  • Siempre hay que evitar la magia del $IFS si basta con un glob, ya que es innecesariamente enrevesado, y los nombres de archivo pueden contener realmente nuevas líneas (pero en la práctica sobre todo la primera razón).

  • Deberías evitar en lo posible analizar manualmente la salida ls y similares, ya que tarde o temprano te morderá. Por ejemplo: en su primera línea awk, falla en todos los nombres de archivo que contienen espacios.

  • printf a menudo le ahorrará problemas al final, ya que es muy robusto con la sintaxis %s. También le da un 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 potente.

  • Sus invocaciones head y tail podrían haber sido manejadas directamente en awk con, por ejemplo, el comando exit y/o seleccionando en la variable NR. Esto ahorraría invocaciones al proceso, lo que casi siempre mejora mucho el rendimiento en los scripts que trabajan mucho.

  • Sus egreps podrían ser simplemente grep.

2
2
2
2011-11-16 22:46:38 +0000

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

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 "";
1
1
1
2015-01-20 18:00:05 +0000

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

No puedes listar los archivos reales con enlaces duros desde “ls” porque, como han señalado los comentaristas anteriores, los “nombres” de los archivos son meros alias de los mismos datos. Sin embargo, existe una herramienta GUI que se acerca mucho a lo que quieres, que es mostrar un listado de rutas de nombres de archivos que apuntan a los mismos datos (como hardlinks) en linux, se llama FSLint. La opción que quieres está en “Name clashes” -> desmarca “checkbox $PATH” en Search (XX) -> y selecciona “Aliases” del cuadro desplegable después de “for…” hacia la parte superior-media.

FSLint está muy mal documentado pero he encontrado que asegurando el árbol de directorios limitado bajo “Search path” con la casilla seleccionada para “Recurse?” y las opciones mencionadas, se produce un listado de datos hardlinked con rutas y nombres que “apuntan” a los mismos datos después de que el programa busca.

1
1
1
2017-12-06 17:34:25 +0000

Puede configurar ls para resaltar los enlaces duros usando un ‘alias’, pero como se ha dicho antes no hay manera de mostrar la ‘fuente’ del enlace duro, por lo que añado .hardlink para ayudar con eso.

Añada lo siguiente en algún lugar de su .bashrc

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