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

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

Je lance

ln /a/A /b/B

Je voudrais voir dans le dossier a où le fichier A pointe vers ls.

Réponses (9)

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

Vous pouvez trouver le numéro d'inode de votre fichier avec

ls -i

et

ls -l

montre le nombre de références (nombre de liens durs vers un inode particulier)

après avoir trouvé le numéro d'inode, vous pouvez rechercher tous les fichiers avec le même inode :

find . -inum NUM

affichera les noms de fichiers pour l'inode NUM dans le répertoire actuel (.)

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

Il n'y a pas vraiment de réponse bien définie à votre question. Contrairement aux liens symboliques, les liens durs sont indissociables du “fichier original”.

Les entrées de répertoire se composent d'un nom de fichier et d'un pointeur vers un inode. L'inode contient à son tour les métadonnées du fichier et (les pointeurs vers) le contenu réel du fichier). La création d'un lien en dur crée un autre nom de fichier + une référence au même inode. Ces références sont unidirectionnelles (du moins dans les systèmes de fichiers typiques) – l'inode ne conserve qu'un compte de références. Il n'y a pas de moyen intrinsèque de savoir quel est le nom de fichier “original”.

Au fait, c'est pourquoi l'appel système pour “supprimer” un fichier est appelé unlink. Il supprime simplement un lien dur. L'inode et les données jointes ne sont supprimés que si le nombre de références de l'inode tombe à 0.

La seule façon de trouver les autres références à un inode donné est de faire une recherche exhaustive dans le système de fichiers en vérifiant quels fichiers se réfèrent à l'inode en question. Vous pouvez utiliser le “test A -ef B” du shell pour effectuer cette vérification.

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

La première colonne représente les autorisations. La deuxième colonne sera le nombre de sous-postes (pour les répertoires) ou le nombre de chemins d'accès aux mêmes données (liens en dur, y compris le fichier original) au fichier. Ex :

-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

Et pourquoi pas la suivante, plus simple ? (Ce dernier pourrait remplacer les longs scripts ci-dessus !)

Si vous avez un fichier spécifique <THEFILENAME>et que vous voulez connaître tous ses liens durs répartis sur le répertoire <TARGETDIR>, (qui peut même être le système de fichiers entier désigné par /)

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

Etendre la logique, si vous voulez connaître tous les fichiers du <SOURCEDIR> ayant plusieurs liens durs répartis sur <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

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

Avec un seul passage sur le système de fichiers pour trouver et regrouper tous les ensembles de fichiers liés en dur

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 plusieurs ensembles de fichiers liés en dur.
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 également le FS-id en uniq sur les répertoires de rejet
  • ! -type d : les entrées . et .. signifient qu'ils sont toujours liés.
  • -links +1 : compte des liens strictement > 1
  • -printf ... : impression du FS-id, du numéro d'inode et du chemin. (Avec un remplissage à des largeurs de colonnes fixes dont nous pouvons dire uniq environ.)
  • sort -n | uniq ... : tri numérique et unification sur les 42 premières colonnes, en séparant les groupes par une ligne blanche

L'utilisation de ! -type d -links +1 signifie que l'entrée du tri est seulement aussi grande que la sortie finale d'uniq, donc nous ne faisons pas un énorme tri de chaînes. Sauf si vous l'exécutez sur un sous-répertoire qui ne contient qu'un seul des 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 proposée.

exemple de sortie :

...
            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écompactez la sortie avec awk ou cut. uniq a un support de sélection de champ très limité, donc je tamponne la sortie de recherche et j'utilise une largeur fixe. 20chars est assez large pour le maximum possible d'inodes ou de numéros de périphériques (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 façon contiguë à partir de 0, de sorte que les grands systèmes de fichiers XFS peuvent avoir des numéros d'inode de >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. Le fait de les trier par point de montage puis par numéro d'inode mélange les choses, si vous avez plusieurs sous-répertoires différents qui ont beaucoup de liens durs. (c'est-à-dire que des groupes de doublons vont ensemble, mais que la sortie les mélange).

Un dernier sort -k 3 trierait les lignes séparément, et non des groupes de lignes comme un seul enregistrement. Un 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 n'opère que sur des caractères uniques, et non sur des modèles 2->1 ou 1->2, cependant. perl pourrait le faire (ou simplement analyser et trier dans perl ou awk). sed pourrait aussi fonctionner.

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

C'est un peu un commentaire sur la réponse et le script de Torocoro-Macho, mais il ne rentre évidemment pas dans la boîte de commentaires.


Réécrivez votre script avec des moyens plus directs de 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 pour faciliter la comparaison.

Commentaires sur ce script et le vôtre

  • Il faut toujours éviter la magie $IFS si un globe suffit, car il est inutilement alambiqué, et les noms de fichiers peuvent en fait contenir des nouvelles lignes (mais en pratique c'est surtout la première raison).

  • Il faut éviter autant que possible d'analyser manuellement la sortie ls et ce genre de sortie, car elle vous mordra tôt ou tard. Par exemple : dans votre première ligne awk, vous échouez sur tous les noms de fichiers contenant des espaces.

  • printf vous évitera souvent des problèmes à la fin, car il est très robuste avec la syntaxe %s. Il vous donne également un contrôle total sur la sortie, et est cohérent sur tous les systèmes, contrairement à echo.

  • stat peut vous épargner beaucoup de logique dans ce cas.

  • GNU find est puissant.

  • Vos invocations head et tail auraient pu être traitées directement dans awk avec, par exemple, la commande exit et/ou en sélectionnant la variable NR. Cela permettrait d'économiser les invocations de processus, qui sont presque toujours plus performantes dans les scripts laborieux.

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

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

Basé sur le script findhardlinks (renommé hard-links), voici ce que j'ai refait et fait fonctionner.

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

&nbsp ;

# 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

Une solution GUI se rapproche vraiment de votre question :

Vous ne pouvez pas lister les fichiers réels liés en dur à partir de “ls” car, comme l'ont souligné les commentateurs précédents, les “noms” des fichiers sont de simples alias des mêmes données. Cependant, il existe en fait un outil graphique qui se rapproche beaucoup de ce que vous souhaitez, c'est-à-dire afficher un chemin d'accès listant les noms de fichiers qui pointent vers les mêmes données (comme les liens durs) sous linux, il s'appelle FSLint. L'option que vous souhaitez se trouve sous “conflits de noms” -> désélectionnez “case à cocher $PATH” dans Recherche (XX) -> et sélectionnez “Alias” dans la liste déroulante après “pour…” vers le haut-médium.

FSLint est très mal 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 mentionnées ci-dessus, 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 les recherches du programme.

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

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'ai ajouté .hardlink pour vous aider.

Ajoutez ce qui suit quelque part dans votre .bashrc

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