151 votes

Comment pouvez-vous voir le lien dur réel par ls ?

Je cours

ln /a/A /b/B

Je voudrais voir dans le dossier a où le fichier A est pointé par ls .

13voto

Peter Cordes Points 5022

Il y a beaucoup de réponses avec scripts pour trouver tous les hardlinks dans un système de fichiers. La plupart d'entre elles font des choses stupides comme lancer find pour scanner tout le système de fichiers à la recherche de -samefile pour CHAQUE fichier à liens multiples. C'est de la folie ; tout ce dont vous avez besoin est de trier sur le numéro d'inode et d'imprimer les doublons.

Il suffit d'un seul passage sur le système de fichiers pour trouver et regrouper tous les ensembles de fichiers liés entre eux.

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

C'est beaucoup plus rapide que les autres réponses pour trouver des ensembles multiples de fichiers liés entre eux.
find /foo -samefile /bar est excellent pour un seul fichier.

  • -xdev : limite à un seul système de fichiers. Pas strictement nécessaire puisque nous imprimons aussi le FS-id à uniq sur
  • ! -type d rejeter les répertoires : le . y .. Les entrées signifient qu'elles sont toujours liées.
  • -links +1 : nombre de liens strictement > 1
  • -printf ... affiche l'identifiant FS, le numéro d'inode et le chemin. (Avec le remplissage à des largeurs de colonne fixes que nous pouvons dire uniq à peu près.)
  • sort -n | uniq ... tri numérique et unicité sur les 42 premières colonnes, en séparant les groupes par une ligne blanche

Utilisation de ! -type d -links +1 signifie que l'entrée de sort est seulement aussi grande que la sortie finale de uniq, donc nous ne faisons pas une énorme quantité de tri de chaînes. A moins que vous ne l'exécutiez sur un sous-répertoire qui ne contient qu'un seul d'un ensemble de liens durs. Quoi qu'il en soit, cela utilisera BEAUCOUP moins de temps CPU pour retraverser le système de fichiers que toute autre solution affichée.

sortie de l'échantillon :

...
            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 : dépaqueter la sortie avec awk o cut . uniq a un support très limité pour la sélection des champs, donc je rembourre la sortie de find et j'utilise une largeur fixe. La largeur de 20 caractères est suffisante pour le numéro maximal possible d'inode ou de périphérique (2^64-1 = 18446744073709551615). XFS choisit les numéros d'inode en fonction de l'endroit du disque où ils sont alloués, et non de manière contiguë à partir de 0, de sorte que les grands systèmes de fichiers XFS peuvent avoir des numéros d'inode >32 bits même s'ils n'ont pas des milliards de fichiers. D'autres systèmes de fichiers peuvent avoir des numéros d'inode à 20 chiffres même s'ils ne sont pas gigantesques.

TODO : trier les groupes de doublons par chemin. Les trier par point de montage puis par numéro d'inode mélange les choses, si vous avez deux sous-répertoires différents qui ont beaucoup de hardlinks. (c'est-à-dire que les groupes de doublons vont ensemble, mais la sortie les mélange).

Une finale sort -k 3 permet de trier les lignes séparément, et non les groupes de lignes comme un seul enregistrement. Le prétraitement avec quelque chose pour transformer une paire de nouvelles lignes en un octet NUL, et l'utilisation de GNU sort --zero-terminated -k 3 pourrait faire l'affaire. tr ne fonctionne que sur des caractères uniques, et non sur des motifs 2->1 ou 1->2. perl le ferait (ou simplement analyser et trier avec perl ou awk). sed pourrait également fonctionner.

4voto

Daniel Andersson Points 22765

Il s'agit en quelque sorte d'un commentaire à la réponse et au script de Torocoro-Macho, mais il ne rentre évidemment pas dans la boîte à commentaires.


Réécriture de votre script avec des moyens plus directs pour trouver l'information, et donc beaucoup moins d'invocations de processus.

#!/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

J'ai essayé de le garder aussi semblable au vôtre que possible pour faciliter la comparaison.

Commentaires sur ce script et le vôtre

  • Il faut toujours éviter $IFS magique si un glob suffit, puisque c'est inutilement alambiqué, et que les noms de fichiers peuvent effectivement contenir des nouvelles lignes (mais en pratique, c'est surtout la première raison).

  • Vous devriez éviter d'analyser manuellement ls et ce genre de production autant que possible, car elle vous mordra tôt ou tard. Par exemple : dans votre premier awk vous échouez sur tous les noms de fichiers contenant des espaces.

  • printf permettra souvent d'éviter des problèmes en fin de compte, car il est si robuste avec les %s la syntaxe. Il vous donne également un contrôle total sur la sortie, et est cohérent à travers todo contrairement aux systèmes echo .

  • stat peut vous faire gagner beaucoup de logique dans ce cas.

  • GNU find est puissant.

  • Votre head y tail auraient pu être traitées directement dans awk avec, par exemple, le exit et/ou en sélectionnant sur le NR variable. Cela permettrait d'économiser les invocations de processus, ce qui améliore presque toujours gravement les performances des scripts qui travaillent dur.

  • Votre egrep pourrait tout aussi bien être juste grep .

3voto

wkw Points 3177

Vous pouvez configurer ls pour mettre en évidence les liens durs en utilisant un 'alias', mais comme indiqué précédemment il n'y a aucun moyen de montrer la 'source' du lien dur, c'est pourquoi j'ajoute .hardlink pour aider à cela.

highlight hardlinks

Ajoutez le texte suivant quelque part dans votre .bashrc

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

2voto

Torocoro-Macho Points 21

Sur la base de la findhardlinks script (renommé en hard-links ), voici ce que j'ai remanié pour que cela fonctionne.

Sortie :

# ./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 "";

1voto

Charles Points 11

Une solution GUI se rapproche vraiment de votre question :

Vous ne pouvez pas lister les fichiers liés en dur à partir de "ls" car, comme les commentateurs précédents l'ont souligné, les "noms" de fichiers sont de simples alias pour les mêmes données. Cependant, il existe en fait un outil GUI qui se rapproche vraiment de ce que vous voulez, c'est-à-dire afficher une liste des chemins d'accès aux noms de fichiers qui pointent vers les mêmes données (en tant que hardlinks) sous linux, il s'appelle FSLint. L'option que vous voulez est sous "Name clashes" -> désélectionnez "checkbox $PATH" dans Search (XX) -> et sélectionnez "Alias" dans la liste déroulante après "for..." vers le haut-milieu.

FSLint est très peu documenté mais j'ai trouvé qu'en s'assurant que l'arbre de répertoire limité sous "Search path" avec la case à cocher sélectionnée pour "Recurse ?" et les options susmentionnées, une liste de données liées avec des chemins et des noms qui "pointent" vers les mêmes données est produite après que le programme ait effectué des recherches.

SistemesEz.com

SystemesEZ est une communauté de sysadmins où vous pouvez résoudre vos problèmes et vos doutes. Vous pouvez consulter les questions des autres sysadmins, poser vos propres questions ou résoudre celles des autres.

Powered by:

X