lien symbolique vers un répertoire et un chemin relatif

15

J'ai créé un lien symbolique avec un chemin absolu vers le répertoire (Blink) et j'ai par exemple l'arborescence suivante:

$ ls -l /tmp/A
total 0
lrwxrwxrwx 1 root root 6 Apr  3 12:27 Blink -> /tmp/B
-rw-r--r-- 1 root root 0 Apr  3 12:27 foo

$ ls -l /tmp/B
total 0
-rw-r--r-- 1 root root 0 Apr  3 12:27 bar

puis je vais dans / tmp / A et je change de répertoire pour Blink:

$ cd /tmp/A
$ pwd
/tmp/A
$ cd Blink
$ pwd
/tmp/A/Blink

cd ..me renvoie /tmp/A mais si je tape par exemple ls ../fooje vais avoir une erreur:

ls: ../foo: No such file or directory

La commande cd intégrée résout le chemin si nécessaire, mais les ls externes considèrent le .. comme un niveau supérieur de / tmp / B et ne peuvent donc pas trouver foo.

Quel est le problème ici? Puis-je obtenir le fichier foo de / tmp / A / Blink par un chemin relatif comme ../foo?

user478681
la source
La même question est transposée
Peter.O

Réponses:

13

Je ne pense pas que vous puissiez faire ça. De nos jours, les shells gardent une trace de comment ils sont arrivés là où ils se trouvent, ils gardent la trace du répertoire de travail actuel par nom, plutôt que de simplement s'appuyer sur le système de fichiers et le système d'exploitation pour le garder. Cela signifie que la fonction intégrée cdpeut "sauvegarder" le lien symbolique, plutôt que de suivre directement les chaînes "..".

Mais lorsque vous exécutez ls ../foo, vous ne savez lspas que le shell a atteint un répertoire en suivant des liens symboliques. lsfera un stat()sur "../foo". La partie ".." provient du répertoire courant, qui n'a qu'une seule entrée ".." pour son parent. L'ensemble du lien symbolique ne change pas la façon dont les répertoires ont un seul "." et une seule entrée "..". Les liens symboliques permettent au noyau d'insérer une couche supplémentaire d'indirection dans les chemins de fichiers. Lorsque vous transmettez "../n'importe quoi" à open()ou stat(), le noyau utilise simplement le répertoire de travail actuel du processus effectuant l'appel pour déterminer quel répertoire unique est nommé par "..".

Bruce Ediger
la source
17

Le shell stocke le répertoire de travail actuel dans $PWD. C'est ce qui est utilisé pour les commandes internes du shell cdet pwd, et il traite les liens symboliques comme des répertoires normaux, comme vous l'avez vu. Parfois, cela est utile, parfois non.

Vous pouvez trouver le vrai répertoire en utilisant pwd(tapez help pwdpour plus de détails):

$ pwd
/tmp/A/Blink
$ pwd -L
/tmp/A/Blink
$ pwd -P
/tmp/B

De même, cda une option -P(encore une fois, help cdest votre ami):

$ cd /tmp/A/Blink
$ pwd
/tmp/A/Blink
$ cd -P ..
$ pwd -P
/tmp

Enfin, vous pouvez désactiver complètement la "fonctionnalité":

$ set -P
$ cd /tmp/A/Blink
$ pwd
/tmp/B
ams
la source
Merci, je suis au courant de la fonction set -P, mais
j'ai été troublé
Comme je l'ai dit, l'utilisation set -Pet le comportement de ls commencent à avoir un sens. :)
ams
2

Bruce et ams ont donné de belles réponses expliquant le comportement derrière. Mais pour faire ce que ls ../foovous demandiez, vous pouvez aller avec quelque chose comme

ls $(dirname $PWD)/foo
Antti Vikman
la source
1

Vous ne pouvez pas le faire, parce que /tmp/A/Blink est en réalité /tmp/B. Alors ls ../A/fooça marche.

Vous pouvez plutôt trouver utile de pouvoir cd au vrai /tmp/B répertoire, plutôt que le crénelage /tmp/A/Blink. Pour ce faire, vous pouvez utiliser la fonction suivante à la place de cd(que vous pouvez mettre dans votre .bashrc)

lcd() { cd $(readlink -f "$1"); }

lcd, bien sûr, fonctionne pour les deux répertoires normaux et liés symboliquement.
Remarque: readlink -fagit sur la cible finale du lien (lorsque les liens sont chaînés).

Peter.O
la source
1
cd -Psemble plus simple.
jw013
@ jw013: Vous avez raison; il est. Je n'étais pas au courant .. merci ..
Peter.O