web-dev-qa-db-fra.com

Déterminer si un fichier est un lien dur ou un lien symbolique?

Je crée un script Shell qui prendrait un nom de fichier/chemin vers un fichier et déterminer si le fichier est un lien symbolique ou un lien dur.

La seule chose est que je ne sais pas si c'est un lien dur. J'ai créé 2 fichiers, l'un un lien dur et l'autre un lien symbolique, à utiliser comme fichier de test. Mais comment pourrais-je déterminer si un fichier est un lien dur ou symbolique dans un script Shell?

De plus, comment trouver la partition de destination d'un lien symbolique? Supposons donc que j'ai un fichier lié à une autre partition, comment trouver le chemin d'accès à ce fichier d'origine?

54
k-Rocker

La réponse de Jim explique comment tester un lien symbolique: en utilisant test's -L test.

Mais tester un "lien dur" n'est pas à proprement parler ce que vous voulez. Les liens matériels fonctionnent en raison de la façon dont Unix gère les fichiers: chaque fichier est représenté par un seul inode. Alors un seul inode a zéro ou plus noms ou entrées de répertoire ou, techniquement, liens durs (ce que vous appelez un "fichier") .

Heureusement, la commande stat, lorsqu'elle est disponible, peut vous indiquer le nombre de noms d'un inode.

Donc, vous cherchez quelque chose comme ça (en supposant ici l'implémentation GNU ou busybox de stat):

if [ "$(stat -c %h -- "$file")" -gt 1 ]; then
    echo "File has more than one name."
fi

Le -c '%h' bit indique à stat de simplement afficher le nombre de liens physiques vers l'inode, c'est-à-dire le nombre de noms du fichier. -gt 1 vérifie ensuite si c'est plus de 1.

Notez que les liens symboliques, comme tout autre fichier, peuvent également être liés à plusieurs répertoires afin que vous puissiez avoir plusieurs liens physiques vers un lien symbolique.

44
derobert

Un exemple:

$ touch f1
$ ln f1 f2
$ ln f1 f3
$ ln -s f1 s1
$ ln -s f2 s2
$ ln -s ./././f3 s3
$ ln -s s3 s4
$ ln s4 s5
$ ls -li
total 0
10802124 -rw-r--r-- 3 stephane stephane 0 Nov 12 19:55 f1
10802124 -rw-r--r-- 3 stephane stephane 0 Nov 12 19:55 f2
10802124 -rw-r--r-- 3 stephane stephane 0 Nov 12 19:55 f3
10802345 lrwxrwxrwx 1 stephane stephane 2 Nov 12 19:56 s1 -> f1
10802346 lrwxrwxrwx 1 stephane stephane 2 Nov 12 19:56 s2 -> f2
10802347 lrwxrwxrwx 1 stephane stephane 8 Nov 12 19:56 s3 -> ./././f3
10802384 lrwxrwxrwx 2 stephane stephane 2 Nov 12 19:56 s4 -> s3
10802384 lrwxrwxrwx 2 stephane stephane 2 Nov 12 19:56 s5 -> s3

Le f1, f2 et f3 les entrées du répertoire sont le même fichier (même inode: 10802124, vous remarquerez le nombre de liens = 3). Ce sont des liens durs vers le même fichier normal.

s4 et s5 sont également le même fichier (10802384). Ils sont de type lien symbolique, pas normal. Ils pointent vers un chemin, ici s3. Parce que s4 et s5 sont des entrées du même répertoire, ce chemin relatif s3 pointe vers le même fichier (celui avec inod 10802347) pour les deux.

Si vous faites un ls -Ll, qui demande d'obtenir des informations sur le fichier après la résolution des liens symboliques:

$ ls -lLi
total 0
10802124 -rw-r--r-- 3 stephane stephane 0 Nov 12 19:55 f1
10802124 -rw-r--r-- 3 stephane stephane 0 Nov 12 19:55 f2
10802124 -rw-r--r-- 3 stephane stephane 0 Nov 12 19:55 f3
10802124 -rw-r--r-- 3 stephane stephane 0 Nov 12 19:55 s1
10802124 -rw-r--r-- 3 stephane stephane 0 Nov 12 19:55 s2
10802124 -rw-r--r-- 3 stephane stephane 0 Nov 12 19:55 s3
10802124 -rw-r--r-- 3 stephane stephane 0 Nov 12 19:55 s4
10802124 -rw-r--r-- 3 stephane stephane 0 Nov 12 19:55 s5

Vous les trouverez tous résoudre dans le même fichier (10802124).

Vous pouvez vérifier si un fichier est un lien symbolique avec [ -L file ]. De même, vous pouvez tester si un fichier est un fichier normal avec [ -f file ], mais dans ce cas, la vérification est effectuée après la résolution des liens symboliques.

les liens physiques ne sont pas un type de fichier, ce sont juste des noms différents pour un fichier (de n'importe quel type).

29
Stéphane Chazelas

En utilisant le -h et -L opérateurs de la commande test:

-h file 
true if file is a symbolic link

-L file 
true if file is a symbolic link

http://www.mkssoftware.com/docs/man1/test.1.asp

Selon this SO thread , ils ont le même comportement, mais -L est préféré.

19
jimm-cl

Il y a beaucoup de réponses tout à fait correctes ici, mais je ne pense pas que quiconque ait vraiment abordé la perception erronée originale. La question d'origine est essentiellement "quand je crée un lien symbolique, il est facile de l'identifier par la suite. Mais je ne peux pas comprendre comment identifier un lien dur." Et oui, les réponses se résument essentiellement à "vous ne pouvez pas" et expliquent plus ou moins pourquoi, mais personne ne semble avoir reconnu que, vraiment, cela IS confus et étrange.

Si vous lisez tout cela et que vous avez compris ce qui se passe, alors vous êtes bon; vous n'avez pas besoin de lire mon petit bout. Si vous êtes toujours confus, continuez.

La réponse vraiment très courte est qu'un lien dur n'est pas vraiment un lien du tout, pas de la même manière qu'un lien symbolique. Il s'agit d'une nouvelle entrée dans la structure de répertoires qui pointe vers le même paquet d'octets que l'entrée de répertoire d'origine, et une fois que vous l'avez créée, elle est tout aussi "réelle" et légitime que la première. Chaque fichier 'normal' sur votre lecteur a au moins un lien dur; sans cela, vous ne le verriez pas dans le répertoire any, et vous ne pourriez pas vous y référer ou l'utiliser. Donc, si vous avez un fichier Fred.txt et que vous liez en dur Wilma.txt et Barney.txt, les trois noms (et entrées de répertoire) font référence au même fichier et ils sont tous également valides. Il n'y a aucun moyen pour le système d'exploitation de dire que l'une des entrées a été créée lorsque vous appuyez sur "enregistrer" dans votre éditeur de texte, et les autres ont été créées avec la commande "ln".

Cependant, l'OS doit doit garder une trace du nombre d'entrées différentes pointant vers le même fichier. Si vous supprimez Wilma.txt, il n'est pas surprenant que vous ne libériez pas d'espace sur votre lecteur. Mais si vous supprimez Fred.txt (le fichier "d'origine"), vous ne libérerez toujours pas d'espace sur votre lecteur, car les données sur le lecteur qui était connu sous le nom de Fred.txt sont toujours également Barney.txt. Ce n'est que lorsque vous supprimez toutes des entrées du répertoire que le système d'exploitation désallouera l'espace que les données elles-mêmes occupaient.

Si Barney.txt avait été un lien symbolique, la suppression de Fred.txt aurait aurait désalloué l'espace, et Barney.txt serait désormais un lien rompu. De plus, si vous déplacez ou renommez un fichier ayant un lien symbolique pointant dessus, vous romprez le lien. Mais vous pouvez déplacer ou renommer un fichier lié en dur tout ce que vous voulez sans casser les autres entrées de répertoire qui pointent vers ce fichier/données, car toutes sont des entrées de répertoire qui font référence au même bloc de données sur le lecteur (en utilisant le # d'inode de ces données).

[C'est deux ans plus tard, et ce dernier peu confus moi pendant une minute, donc je pense que je vais clarifier. Si vous tapez "mv ./Wilma.txt ../elsewhere/Betty.txt", il semble que vous déplacez le fichier, mais en fait, ce n'est pas le cas. Ce que vous faites vraiment, c'est de supprimer un élément de ligne de la liste des répertoires de votre répertoire actuel, celui qui dit "le nom 'Wilma.txt' est associé aux données qui peuvent être trouvées en utilisant l'inode ###### # ", et en ajoutant un nouvel élément de campagne à la liste de répertoires du répertoire ../elsewhere qui dit" le nom 'Betty.txt' est associé aux données qui peuvent être trouvées via l'inode ####### ". C'est pourquoi vous pouvez "déplacer" un fichier de 2 gigaoctets aussi rapidement qu'un fichier de 2 kilo-octets, tant que vous les déplacez vers un autre emplacement sur le même lecteur.]

Parce que le système d'exploitation doit garder une trace du nombre d'entrées de répertoire différentes pointant vers le même bloc de données, vous pouvez dire si un fichier particulier a été lié dur, même si vous ne pouvez pas le dire certain que l'entrée de répertoire que vous regardez est celle "originale" ou non. Une façon est la commande "ls", spécifiquement "ls -l" (c'est un L minuscule après le tiret)

Pour emprunter un exemple précédent ...

 -rw-r--r-- 3 stephane stephane 0 Nov 12 19:55 f1

La première lettre est un tiret, donc ce n'est pas un répertoire ou quelque chose d'autre exotique, c'est un fichier ordinaire "normal". Mais si c'était vraiment ordinaire, ce nombre après la partie rwx-ish serait "1", comme dans "il y a une entrée de répertoire pointant vers ce bloc de données". Mais cela fait partie d'une démonstration de liens durs, donc à la place, il est dit "3".

Notez que cela peut éventuellement conduire à un comportement étrange et mystérieux (si vous n'avez pas enroulé votre tête autour de liens durs, c'est-à-dire). Si vous ouvrez Fred.txt dans votre éditeur de texte et apportez des modifications, verrez-vous les mêmes modifications dans Wilma.txt et Barney.txt? Peut être. Probablement. Si votre éditeur de texte enregistre les modifications en ouvrant le fichier d'origine et en y écrivant, alors oui, les trois noms pointeront toujours vers le même texte (nouvellement modifié). Mais si votre éditeur de texte crée un nouveau fichier (Fred-new-temp.txt), y écrit votre version modifiée, puis supprime Fred.txt, puis renomme Fred-new-temp.txt en Fred.txt, Wilma et Barney pointe toujours vers la version originale, pas la nouvelle version modifiée. Si vous ne comprenez pas les liens durs, cela pourrait vous rendre légèrement fou. :) [D'accord, je ne connais personnellement personne éditeurs de texte qui ferait le nouveau fichier/renommer, mais je connais beaucoup d'autres programmes qui font exactement cela, alors restez alerte.]

Une dernière note: une des choses que 'fsck' (vérification du système de fichiers) vérifie est s'il y a des blocs de données sur votre disque qui ne sont plus référencés par aucune entrée de répertoire. Parfois, quelque chose ne va pas, et la seule entrée de répertoire qui pointe vers un inode est supprimée mais l'espace disque lui-même n'est pas marqué comme "disponible". Ainsi, l'un des travaux de fsck consiste à faire correspondre tout l'espace alloué avec toutes les entrées du répertoire pour vous assurer qu'il n'y a pas de fichiers non référencés. S'il en trouve, il crée de nouvelles entrées de répertoire et les place dans "perdu + trouvé".

4
Snarke

vous pouvez utiliser readlink FILE; echo $?. Cela renvoie 1 lorsqu'il s'agit d'un lien dur et 0 lorsqu'il s'agit d'un lien symbolique.

À partir de la page de manuel: "Lorsqu'il est appelé en tant que lien de lecture, seule la cible du lien symbolique est imprimée. Si l'argument donné n'est pas un lien symbolique, readlink n'imprimera rien et quittera avec une erreur."

3
user2103720