Corro
ln /a/A /b/B
Me gustaría ver en la carpeta a
donde están los puntos a presentar una por ls
.
Corro
ln /a/A /b/B
Me gustaría ver en la carpeta a
donde están los puntos a presentar una por ls
.
Respuestas:
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 duros 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 inode NUM en el directorio actual (.)
Realmente no hay una respuesta bien definida a su pregunta. A diferencia de los enlaces simbólicos, los enlaces duros no se pueden distinguir 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 (apunta 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 cual se llama al sistema para "eliminar" un archivo unlink
. Simplemente elimina un enlace duro. El inodo y los datos adjuntos se eliminan solo si el recuento de referencia del inodo cae a 0.
La única forma de encontrar las otras referencias a un inodo dado es buscar exhaustivamente en el sistema de archivos comprobando qué archivos se refieren al inodo en cuestión. Puede usar 'prueba A -ef B' desde el shell para realizar esta verificación.
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 exactos mismos datos subyacentes. Los datos en un archivo se especifican por su inode
. Cada archivo en un sistema de archivos apunta a un inodo, pero no es necesario 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 privilegiado, todos son iguales. El área de datos solo se liberará cuando se eliminen todos los archivos que usan ese inodo (y todos los procesos también lo cierran, pero ese es un problema diferente).
Puede usar el "ls -i"
comando para obtener el inodo de un archivo en particular. Luego puede usar el "find <filesystemroot> -inum <inode>"
comando para buscar todos los archivos en el sistema de archivos con ese inodo dado.
Aquí hay un script 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:
pax@daemonspawn:~# ./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
. ./findhardlinks.bash
mientras estoy en Zsh de OS X. Mi ventana actual en la pantalla se cierra.
INUM=$(stat -c %i $1)
. También NUM_LINKS=$(stat -c %h $1)
. Consulte man stat
para ver más variables de formato que puede usar.
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 duros, incluido el archivo original) al archivo. P.ej:
-rw-r--r--@ 2 [username] [group] [timestamp] HardLink
-rw-r--r--@ 2 [username] [group] [timestamp] Original
^ Number of hard links to the data
inode
que a su vez apunta al contenido del disco.
¿Qué tal el siguiente más simple? (¡Este último podría reemplazar los largos guiones de arriba!)
Si tiene un archivo específico <THEFILENAME>
y desea conocer todos sus enlaces rígidos distribuidos en el directorio <TARGETDIR>
(que incluso puede ser todo el sistema de archivos indicado por /
)
find <TARGETDIR> -type f -samefile <THEFILENAME>
Extendiendo la lógica, si desea conocer todos los archivos que <SOURCEDIR>
tienen múltiples enlaces duros distribuidos en <TARGETDIR>
:
find <SOURCEDIR> -type f -links +1 \
-printf "\n\n %n HardLinks of file : %H/%f \n" \
-exec find <TARGETDIR> -type f -samefile {} \;
-type f
porque el archivo también puede ser un directorio.
.
y ..
en los directorios son enlaces duros. Puede saber cuántos subdirectores hay en un directorio a partir del recuento de enlaces de .
. Esto es discutible de todos modos, ya que find -samefile .
todavía no imprimirá ningún subdir/..
resultado. find
(al menos la versión GNU) parece ser difícil de ignorar ..
, incluso con -noleaf
.
O(n^2)
, y se ejecuta find
una vez para cada miembro de un conjunto de archivos vinculados. find ... -printf '%16i %p\n' | sort -n | uniq -w 16 --all-repeated=separate
funcionaría, (16 no es lo suficientemente ancho para una representación decimal de 2 ^ 63-1, por lo que cuando su sistema de archivos XFS es lo suficientemente grande como para tener números de inodo tan altos, tenga cuidado)
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 ejecutar find para escanear todo el sistema de archivos en -samefile
busca de CADA archivo con enlaces múltiples. Esto es Loco; todo lo que necesita es ordenar el número de inodo e imprimir duplicados.
Con solo una pasada sobre el sistema de archivos para buscar y agrupar todos los conjuntos de archivos enlazados
find dirs -xdev \! -type d -links +1 -printf '%20D %20i %p\n' |
sort -n | uniq -w 42 --all-repeated=separate
Esto es mucho más rápido que las otras respuestas para encontrar múltiples conjuntos de archivos enlazados.
find /foo -samefile /bar
es excelente para solo un archivo.
-xdev
: límite a un sistema de archivos. No es estrictamente necesario ya que también imprimimos el FS-id para uniq en! -type d
rechazar directorios: las entradas .
y ..
significan que siempre están vinculados.-links +1
: enlace cuenta estrictamente > 1
-printf ...
imprime FS-id, número de inodo y ruta. (Con relleno para anchos de columna fijos de los que podemos hablar uniq
).sort -n | uniq ...
ordenación numérica y uniquificación en las primeras 42 columnas, separando grupos con una línea en blancoEl uso ! -type d -links +1
significa que la entrada de clasificación es tan grande como la salida final de uniq, por lo que no estamos haciendo una gran cantidad de clasificación de cadenas. A menos que lo ejecute en un subdirectorio que solo contiene uno de un conjunto de enlaces duros. De todos modos, esto usará MUCHO menos tiempo de CPU para volver a recorrer 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 ?: descomprime la salida con awk
o cut
. uniq
tiene un soporte de selección de campo muy limitado, por lo que relleno la salida de búsqueda y uso ancho fijo. 20 caracteres es lo suficientemente ancho para el máximo número posible de inodo o dispositivo (2 ^ 64-1 = 18446744073709551615). XFS elige los números de inodo según el lugar del disco en el que están asignados, no contiguamente desde 0, por lo que los sistemas de archivos XFS grandes pueden tener números de inodo> 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 gigantes.
TODO: ordena los grupos de duplicados por ruta. Tenerlos ordenados por punto de montaje y luego número de inodo mezcla cosas juntas, si tiene un par de subdirecciones diferentes que tienen muchos enlaces duros. (es decir, grupos de grupos dobles van juntos, pero la salida los mezcla).
Una final sort -k 3
ordenaría las líneas por separado, no grupos de líneas como un solo registro. El preprocesamiento con algo para transformar un par de líneas nuevas en un byte NUL, y el uso de GNU sort --zero-terminated -k 3
podría ser el truco. tr
Sin embargo, solo funciona con caracteres individuales, no con patrones 2-> 1 o 1-> 2. perl
lo haría (o simplemente analizar y ordenar dentro de perl o awk). sed
También podría funcionar.
%D
es el identificador de sistema de archivos (que es único para el inicio actual, mientras que no hay sistemas de ficheros se umount
ed), por lo siguiente es incluso más genérica: find directories.. -xdev ! -type d -links +1 -printf '%20i %20D %p\n' | sort -n | uniq -w 42 --all-repeated=separate
. Esto funciona siempre que ningún directorio dado contenga otro directorio en el nivel del sistema de archivos, también analiza todo lo que se puede vincular (como dispositivos o enlaces programables; sí, los enlaces programables pueden tener un recuento de enlaces mayor que 1). Tenga en cuenta que dev_t
y ino_t
tiene 64 bits de largo hoy. Esto probablemente se mantendrá mientras tengamos sistemas de 64 bits.
! -type d
, en lugar de -type f
. Incluso tengo algunos enlaces simbólicos enlazados en mi sistema de archivos por organizar algunas colecciones de archivos. Actualicé mi respuesta con su versión mejorada (pero puse el id de fs primero, por lo que el orden de clasificación al menos se agrupa por sistema de archivos)
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.
Reescribió su script con formas más directas de encontrar la información y, por lo tanto, muchas menos invocaciones de proceso.
#!/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
Traté de mantenerlo lo más similar posible al suyo para facilitar la comparación.
Uno siempre debe evitar la $IFS
magia 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 el análisis manual ls
y la salida de este tipo tanto como sea posible, ya que tarde o temprano lo morderá. Por ejemplo: en su primera awk
línea, falla en todos los nombres de archivos que contienen espacios.
printf
a menudo ahorrará problemas al final ya que es muy robusto con la %s
sintaxis. También le brinda control total sobre la salida, y es consistente en todos los sistemas, a diferencia echo
.
stat
puede ahorrarle mucha lógica en este caso.
GNU find
es poderoso
Sus invocaciones head
y tail
podrían haberse manejado directamente awk
con, por ejemplo, el exit
comando y / o la selección en la NR
variable. Esto ahorraría invocaciones de procesos, que casi siempre mejoran severamente el rendimiento en scripts de trabajo duro.
Tu egrep
s bien podría ser justo grep
.
find ... -xdev -type f -links +1 -printf '%16i %p\n' | sort -n | uniq -w 16 --all-repeated=separate
. Esto es MUCHO más rápido, ya que solo atraviesa el fs una vez. Para múltiples FSes a la vez, necesitará prefijar los números de inodo con una identificación FS. Quizás confind -exec stat... -printf ...
Basado en el findhardlinks
script (renombrado como hard-links
), esto es lo que he refactorizado y lo hice 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 "";
Una solución GUI se acerca mucho a su pregunta:
No puede enumerar los archivos vinculados reales de "ls" porque, como han señalado los comentaristas anteriores, los "nombres" de los archivos son meros alias de los mismos datos. Sin embargo, en realidad hay una herramienta GUI que se acerca mucho a lo que desea, que es mostrar una lista de rutas de nombres de archivos que apuntan a los mismos datos (como enlaces duros) en Linux, se llama FSLint. La opción que desea está en "Choques de nombres" -> deseleccione "casilla de verificación $ RUTA" en Buscar (XX) -> y seleccione "Alias" en el cuadro desplegable después de "para ..." hacia la parte superior central.
FSLint está muy poco documentado, pero descubrí que asegurándose de que el árbol de directorios limitado en "Ruta de búsqueda" con la casilla de verificación seleccionada para "¿Recurrir?" y las opciones antes mencionadas, una lista de datos vinculados con rutas y nombres que "apuntan" a los mismos datos se producen después de las búsquedas del programa.
Puede configurar ls
para resaltar los enlaces duros usando un 'alias', pero como se indicó anteriormente, no hay forma de mostrar la 'fuente' del enlace duro, por lo que anexo .hardlink
ayuda con eso.
Agregue 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'
link(2)
llamada al sistema, no tiene sentido cuál es el original y el enlace. Por eso, como señalan las respuestas, la única forma de encontrar todos los enlaces esfind / -samefile /a/A
. Porque una entrada de directorio para un inodo no "conoce" otras entradas de directorio para el mismo inodo. Todo lo que hacen es volver a contar el inodo para que se pueda eliminar cuando el apellido esunlink(2)ed
. (Este es el "conteo de enlaces" en lals
salida).