La cible de symlink est-elle relative au répertoire parent de la destination et si oui, pourquoi?

14

J'ai la structure de fichiers suivante:

build/
client/
  –> index.js

Et quand j'essaie de créer un lien symbolique nommé "client" à l'intérieur du répertoire de construction qui fait référence au répertoire client dans le cwd comme si

// Fails
$ pwd
/home/user/
$ ln -s client build/client 
$ stat build/client/index.js
stat: build/client/index.js: stat: Too many levels of symbolic links

J'obtiens l'erreur ELOOP affichée ci-dessus. Lorsque je modifie le chemin cible pour qu'il soit relatif au chemin de destination, tout va bien:

// Works
$ pwd
/home/user/
$ ln -s ../client build/client 
$ stat build/client/index.js
stat: <outputs file stats>

Est-ce le comportement souhaité et veuillez expliquer pourquoi ...

jibsales
la source
cela a probablement quelque chose à voir avec l'effet que l'utilisation de ../ utilise le chemin absolu pour déclarer le chemin au lieu du chemin relatif. une bonne pratique est de toujours utiliser le chemin absolu
Kiwy
Je suis d'accord avec la meilleure pratique car j'ai toujours utilisé des chemins absolus pour la cible et la destination. Cependant, les pages de manuel indiquent que les chemins relatifs peuvent être utilisés pour les deux ...
jibsales

Réponses:

13

Pour celui qui ne fonctionne pas, si nous regardons le ls -lrésultat, nous obtenons ce qui suit:

[sparticvs@sparta test]$ ls -l build/
total 0
lrwxrwxrwx. 1 sparticvs sparticvs 6 Dec 17 16:08 client -> client

Maintenant, pour comprendre ce qui se passe ici. Regardons la commande que vous avez appelée:

ln -s client build/client

Selon la page de manuel, il existe deux correspondances possibles pour ce format

SYNOPSIS
       ln [OPTION]... [-T] TARGET LINK_NAME   (1st form)
       ln [OPTION]... TARGET... DIRECTORY     (3rd form)

Il correspondra sur la première forme (depuis sa première). Maintenant, le "nom cible" ou clientdans votre cas, peut être (selon le lnmanuel complet ) des chaînes arbitraires. Ils n'ont pas à se résoudre à quoi que ce soit en ce moment, mais peuvent se résoudre à quelque chose à l'avenir. Ce que vous créez avec votre invocation est un "lien symbolique pendant" et le système ne vous empêche pas de les créer.

Maintenant, votre deuxième invocation ln -s ../client build/clientest ce qu'on appelle un "lien symbolique relatif" (comme vous l'avez noté dans votre propre article). Il existe un deuxième type et c'est un "lien symbolique absolu" qui serait appelé en faisant ln -s /home/user/client build/client.

Ce n'est pas un bug. Selon le manuel, il indique:

Lors de la création d'un lien symbolique relatif à un emplacement différent du répertoire actuel, la résolution du lien symbolique sera différente de la résolution de la même chaîne du répertoire actuel. Par conséquent, de nombreux utilisateurs préfèrent d'abord modifier les répertoires à l'emplacement où le lien symbolique relatif sera créé, de sorte que la complétion de tabulation ou une autre résolution de fichier trouve la même cible que celle qui sera placée dans le lien symbolique.

-- de info coreutils 'ln invocation'

Cela dit, vous DEVEZ utiliser le chemin relatif ou absolu vers la cible.

sparticvs
la source
5

C'est bien le comportement recherché. Depuis la ln(1)page de manuel:

Les liens symboliques peuvent contenir du texte arbitraire; s'il est résolu ultérieurement, un lien relatif est interprété par rapport à son répertoire parent.

Quant à savoir pourquoi, imaginez si le lien symbolique a plutôt été interprété par rapport à sa source plutôt qu'à sa destination. Lors de sa résolution ultérieure, vous devrez savoir quel était votre CWD lorsque vous l'avez créé, ce qui est absurde, et encore moins impossible.

De plus, de cette façon, vous obtenez une méthode soignée et compacte pour créer une structure de répertoire squelette que vous pouvez déposer n'importe où dans l'arborescence de répertoires sans casser les liens symboliques.

Pour vous donner un exemple de ce que je veux dire, disons que vous travaillez sur un projet et que vous avez une structure de répertoires entière configurée pour cela comme ceci:

$ ls -1 /home/you/project
thingummies/
widgets/
wizardry/

Supposons maintenant que vous vouliez créer un lien symbolique vers l' widgets/intérieur wizardry/. Vous avez deux options:

$ ln -s /home/you/project/widgets /home/you/project/wizardry

ou

$ ln -s ../widgets /home/you/project/wizardry

Si vous essayez ensuite de vous déplacer /home/you/projectailleurs, un lien symbolique créé avec le premier formulaire se brisera car il est à la recherche /home/you/project/widgets. Le deuxième formulaire gardera le lien symbolique fonctionnel car il recherche par ../widgets rapport à l'endroit où il se trouve, quel que soit l'endroit où cet endroit pourrait être dans l'arborescence de répertoires.

Joseph R.
la source