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

52

Je crée un script shell qui prend un nom de fichier / chemin d'accès à un fichier et détermine si le fichier est un lien symbolique ou un lien dur.

La seule chose est, je ne sais pas comment voir si elles sont un lien dur. J'ai créé 2 fichiers, un lien physique et un lien symbolique, à utiliser comme fichier test. Mais comment déterminer si un fichier est un lien physique ou symbolique dans un script shell?

Aussi, comment pourrais-je trouver la partition de destination d'un lien symbolique? Alors disons que j'ai un fichier qui relie à une partition différente, comment pourrais-je trouver le chemin d'accès à ce fichier original?

k-rocker
la source
16
Qu'entendez-vous par lien dur? Tous les fichiers sont des liens durs.
terdon
1
@terdon ln /foo/bar/ /foo/bar2crée un ln -s /foo/bar /foo/bar2lien dur tout en faisant un lien symbolique, que veut-il dire?
DisplayName
14
@ NomAffichage Oui, mais tous les fichiers sont des liens en dur vers leur inode. C'est ainsi que fonctionnent les systèmes de fichiers Linux. Dans votre exemple, bar2et barsont les deux liens durs, pointant simplement sur le même inode.
terdon
10
@ NomAffichage Oui, ce sont des liens durs vers d'autres inodes . Il n'y a pas de contradiction ici. Un fichier est un lien vers un inode. C'est la définition d'un fichier. Dans votre cas, vous avez ces liens à différents endroits mais cela ne change pas la structure de données sous-jacente. Mon point est que les deux baret bar2sont d'égale importance. L'un n'est pas un lien vers l'autre, ce sont les deux liens mais pointent vers le même inode.
terdon
3
@ Scott Non, je dis que les fichiers normaux sont des liens fixes et que les liens créés par lnne sont pas différents des fichiers normaux.
terdon

Réponses:

42

La réponse de Jim explique comment tester un lien symbolique: en utilisant testle -Ltest de.

Mais tester un "lien dur" n’est, à proprement parler, pas ce que vous voulez. Les liens physiques fonctionnent à cause de la manière dont Unix gère les fichiers: chaque fichier est représenté par un seul inode. Ensuite, un seul inode a zéro ou plusieurs noms ou entrées de répertoire ou, techniquement, des liens physiques (ce que vous appelez un "fichier").

Heureusement, la statcommande, si elle est disponible, peut vous dire combien de noms un inode a.

Donc, vous recherchez quelque chose comme ceci (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 statde simplement sortir le nombre de liens durs vers l'inode, c'est-à-dire le nombre de noms du fichier. -gt 1puis vérifie si c'est plus que 1.

Notez que les liens symboliques, comme tous les autres fichiers, peuvent également être liés à plusieurs répertoires afin que vous puissiez avoir plusieurs liens durs vers un seul lien symbolique.

derobert
la source
ok, juste pour être clair, je peux sortir le nombre de liens durs que le fichier a en utilisant la commande stat et si son supérieur à 1, alors il a un autre fichier lié quelque part sur la partition.
K-Rocker
@ k-rocker oui. Ensuite, il a un deuxième nom quelque part sur la partition.
derobert
1
Sous OS X ou * BSD, c'est stat -f %l /path/to/file. Vous pouvez également utiliser gstat -c %h /path/to/filele logiciel si vous avez installé les coreutils GNU sans leurs noms par défaut (avec Homebrew sous OS X).
GDP2
29

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

Les f1, f2et les f3entrées du répertoire sont le même fichier (même inode: 10802124, vous remarquerez que le nombre de liens est 3). Ce sont des liens en dur vers le même fichier régulier .

s4et s5sont également le même fichier (10802384). Ils sont de type symlink , pas réguliers . Ils indiquent un chemin, ici s3. Etant donné que s4et s5sont des entrées du même répertoire, ce chemin relatif s3pointe vers le même fichier (celui avec inod 10802347) pour les deux.

Si vous faites un ls -Ll, cela 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 constaterez qu'ils résolvent tous 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 durs ne sont pas un type de fichier, ils ne sont que des noms différents pour un fichier (de tout type).

Stéphane Chazelas
la source
19

Utilisation des opérateurs -het -Lde la testcommande:

-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 ce fil SO , ils ont le même comportement, mais -Lest préféré.

jimm-cl
la source
ok cool, mais qu'en est-il des liens durs? J'ai vérifié la marche, mais rien sur les liens durs. Si -L renvoie false, cela signifie-t-il que c'est un lien dur? ou juste un fichier régulier?
K-Rocker
1
Les liens durs partagent la même chose inode. De plus, les liens symboliques affichent un lau début de sa ls -lsortie ... Je pense que vous pourrez peut-être regrouper ces règles dans un script, ainsi que le [[ -L file ]]test permettant de voir si le fichier donné est souple ou matériel .
Jimm-cl
ok, aussi, comment trouverais-je la partition de destination du lien symbolique?
K-Rocker
3

Il y a beaucoup de réponses tout à fait correctes ici, mais je ne pense pas que quiconque se soit réellement attaqué à la perception erronée initiale. La question initiale est fondamentalement "quand je fais un lien symbolique, il est facile de l'identifier après. Mais je ne peux pas trouver comment identifier un lien dur." Et oui, les réponses se résument en gros à «vous ne pouvez pas» et expliquent plus ou moins pourquoi, mais personne ne semble l'avoir reconnu. En réalité, c'est un peu déroutant et étrange.

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

La réponse vraiment courte est qu'un lien dur n'est pas vraiment un lien, pas un lien symbolique. Il s'agit d'une nouvelle entrée dans la structure de répertoires qui pointe vers le même groupe d'octets que l'entrée de répertoire d'origine. 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 comporte au moins un lien physique; sans cela, vous ne le verriez jamaisrépertoire, et serait incapable de s'y référer ou de l'utiliser. Ainsi, si vous avez un fichier Fred.txt et que vous y associez 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. Le système d'exploitation n'a aucun moyen de savoir qu'une des entrées a été créée lorsque vous cliquez sur "Enregistrer" dans votre éditeur de texte et les autres avec la commande "ln".

Le système d'exploitation doit cependant savoir combien d'entrées différentes pointent vers le même fichier. Si vous supprimez Wilma.txt, il n’est pas surprenant que vous ne libériez aucun espace sur votre lecteur. Mais si vous supprimez Fred.txt (le fichier "original"), vous ne libérerez toujours aucun espace sur votre lecteur, car les données sur le lecteur qui s'appelait Fred.txt sont toujours aussi Barney.txt. Ce n'est que lorsque vous supprimez toutes les entrées du répertoire que le système d'exploitation désaffectera l'espace occupé par les données elles-mêmes.

Si Barney.txt avait été un lien symbolique, la suppression de Fred.txt aurait annulé l’espace et Barney.txt serait désormais un lien rompu. De même, si vous déplacez ou renommez un fichier contenant un lien symbolique, vous rompez le lien. Mais vous pouvez déplacer ou renommer un fichier lié en dur sans supprimer les autres entrées de répertoire pointant vers ce fichier / cette donnée, car elles sont toutes des entrées de répertoire qui font référence au même bloc de données sur le lecteur (en utilisant inode # de ces données).

[C'est deux ans plus tard, et ce dernier élément m'a dérouté pendant une minute, alors 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 réalité vous ne l'êtes pas. En réalité, vous supprimez un élément de campagne de la liste de répertoires de votre répertoire actuel, celui qui indique "le nom" Wilma.txt "est associé aux données pouvant être trouvées à l'aide de inode ######. #, "et ajouter un nouvel élément de ligne à la liste de répertoires du répertoire ../elsewhere qui indique" le nom 'Betty.txt' est associé aux données qui peuvent être trouvées via inode ####### ". C'est pourquoi vous pouvez "déplacer" un fichier de 2 gigaoctets aussi rapidement qu'un fichier de 2 kilo-octets, à condition que vous les déplaciez vers un autre emplacement du même lecteur.]

Étant donné que le système d’exploitation doit savoir combien d’entrées de répertoire différentes pointent vers le même bloc de données, vous pouvez savoir si un fichier a été lié à un fichier particulier, même si vous ne pouvez pas savoir avec certitude si l’entrée de répertoire que vous avez regardons est l'original ou pas. Une façon est la commande "ls", plus précisément "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'exotique, c'est un fichier ordinaire. Mais s'il é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 on dit "3".

Notez que cela peut éventuellement conduire à un comportement étrange et mystérieux (si vous ne vous êtes pas entouré 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 les écrivant, alors oui, les trois noms seront toujours dirigés vers le même texte (récemment modifié). Mais si votre éditeur de texte crée un nouveau fichier (Fred-new-temp.txt), y écrit la version modifiée, supprime Fred.txt, puis renomme Fred-new-temp.txt en Fred.txt. Wilma et Barney toujours être pointé vers la version originale, pas la nouvelle version modifiée. Si vous ne comprenez pas les liens physiques, cela pourrait vous rendre légèrement fou. :) [D'accord, je ne connais personnellement aucunles éditeurs de texte qui feraient le nouveau fichier / renommer, mais je connais de nombreux autres programmes qui font exactement cela, alors restez vigilants.]

Une dernière remarque: une des choses que fsck (vérification du système de fichiers) recherche, c’est s’il existe des blocs de données sur votre lecteur qui d’une manière ou d’une autre 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'une des tâches de fsck consiste à faire correspondre tout l'espace alloué avec toutes les entrées de répertoire pour s'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 dans le répertoire et les met dans "lost + found".

Snarke
la source
Je me demandais simplement quels sont ces "autres programmes qui font exactement cela"?
phk
@phk Je ne sais pas à quoi il pense précisément, mais c'est une approche assez commune pour faire des actions qui peuvent durer longtemps et vous laisser dans un état incertain en cas d'échec. Par exemple, si vous essayez de télécharger à partir d'un serveur distant et que vous savez qu'il est possible que le serveur arrive à expiration, une solution consiste à télécharger l'intégralité du contenu dans un fichier temporaire. Ainsi, si quelque chose ne va pas avec le téléchargement, vous avez toujours le fichier original.
cwallenpoole
Le seul programme dont je suis certain est FreeHand, car si / quand il se bloque lors d'une sauvegarde, il reste un fichier temporaire, plutôt qu'un fichier d'origine mutilé. Mais j'ai vu d'autres programmes le faire aussi; Je ne peux tout simplement pas vous donner d'exemples précis pour le moment.
Snarke
2

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

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

utilisateur2103720
la source