Twitter iPhone pliant OnePlus 11 PS5 Disney+ Orange Livebox Windows 11

cp, chemins relatifs et liens symboliques

14 réponses
Avatar
mpg
Bonjour,

Soient deux répertoires A et B (dans mon home, mettons), C un
sous-répertoire de A, et D un lien symbolique placé dans B et pointant vers
C. Si, depuis B, je fais 'cd D', et que j'affiche PWD,
j'obtiens /home/moi/B/D. Si je fais 'cd ..' je reviens dans B. Si par
contre, je choisis un fichier F de C, et que, au moment où mon PWD
est /home/moi/B/D, je fais 'cp F ..', F se retrouve dans A.

Je trouve ça assez troublant : est-ce que c'est un comportement normal ?
Quelle est la logique derrière ça ?

Je connais l'option -P de cd qui permet de savoir toujours où on est pour de
vrai et évite les ambiguïtés, mais parfois j'utilise des liens symboliques
pointant vers un répertoire « profond » dans la hiérarchie, et c'est
justement pour ne pas avoir à me farcir le chemin complet à chaque fois (en
même temps, il y a une notion de répertoire nommé sous zsh je crois, ça
doit aider...)

Manuel.

10 réponses

1 2
Avatar
Jogo
Sur fr.comp.os.unix, mpg disait :

Soient deux répertoires A et B (dans mon home, mettons), C un
sous-répertoire de A, et D un lien symbolique placé dans B et
pointant vers C. Si, depuis B, je fais 'cd D', et que j'affiche PWD,
j'obtiens /home/moi/B/D.


Oui mais si tu lances /bin/pwd tu auras /home/moi/A/C.

Si je fais 'cd ..' je reviens dans B. Si par contre, je choisis un
fichier F de C, et que, au moment où mon PWD est /home/moi/B/D, je
fais 'cp F ..', F se retrouve dans A.

Je trouve ça assez troublant : est-ce que c'est un comportement
normal ? Quelle est la logique derrière ça ?


Ce qui est troublant c'est le fonctionnement exact de cd. Voir la page
de manuel ou :
http://www.opengroup.org/onlinepubs/009695399/utilities/cd.html

--- Extrait ---
8. The curpath value shall then be converted to canonical form as
follows, considering each component from beginning to end, in sequence:

[snip]

b. For each dot-dot component, if there is a preceding component and
it is neither root nor dot-dot, the preceding component, all slashes
separating the preceding component from dot-dot, dot-dot and all
slashes separating dot-dot from the following component shall be
deleted.
--- ---

cp lui se comporte de manière simple : .. est un hard link
de /home/moi/A.

--
Don't everyone thank me at once!
-- Han Solo

Avatar
Vincent Lefevre
Dans l'article <fj1arr$2cb9$,
mpg écrit:

Soient deux répertoires A et B (dans mon home, mettons), C un
sous-répertoire de A, et D un lien symbolique placé dans B et pointant vers
C. Si, depuis B, je fais 'cd D', et que j'affiche PWD,
j'obtiens /home/moi/B/D.


Avec zsh et les bonnes options (CHASE_LINKS, ce qui implique CHASE_DOTS):

vin:~/B> ll
total 0
lrwxrwxrwx 1 vlefevre vlefevre 18 2007-12-03 18:52:36 D -> /home/vlefevre/A/C/
vin:~/B> cd D
vin:~/A/C> pwd
/home/vlefevre/A/C

Le fait que le shell te dise /home/moi/B/D donne des incohérences,
comme tu as pu t'en apercevoir:

Si je fais 'cd ..' je reviens dans B. Si par contre, je choisis un
fichier F de C, et que, au moment où mon PWD est /home/moi/B/D, je
fais 'cp F ..', F se retrouve dans A.

Je trouve ça assez troublant : est-ce que c'est un comportement normal ?
Quelle est la logique derrière ça ?


Le problème est que le .. peut avoir deux sens:

1. '..' étant un répertoire comme un autre, on le résout en ce répertoire,
i.e. A (n'oublie pas que le véritable répertoire est A/C, donc A/C/..
est réellement A).

2. '..' peut vouloir dire: supprimer la dernière composante du répertoire
considéré, ce qui donne un résultat différent si les liens symboliques
n'ont pas été résolus en leur véritable valeur lors du cd.

Le principal problème est dû que B/D n'est pas un véritable répertoire;
c'est juste un nom construit via des liens symboliques. C'est pour cela
que remplacer le nom par le véritable nom canonique en n'ayant plus de
lien symbolique est préférable. C'est mieux aussi question sécurité: on
sait exactement où on se trouve. Pas exemple, imagine le cas où B est
"privé", mais A et C sont "publics". Si le shell te montre B/D, tu vas
croire que tu es dans un répertoire privé alors que c'est en fait A/C
que tout le monde peut lire.

J'ai d'ailleurs dans mon .zshenv:

setopt CHASE_LINKS

suite à ça:

http://www.zsh.org/mla/workers/2004/msg00937.html

Je connais l'option -P de cd qui permet de savoir toujours où on est pour de
vrai et évite les ambiguïtés, mais parfois j'utilise des liens symboliques
pointant vers un répertoire « profond » dans la hiérarchie, et c'est
justement pour ne pas avoir à me farcir le chemin complet à chaque fois (en
même temps, il y a une notion de répertoire nommé sous zsh je crois, ça
doit aider...)


Oui, j'utilise beaucoup les répertoires nommés (sinon, les variables
d'environnement peuvent parfois aider).

--
Vincent Lefèvre - Web: <http://www.vinc17.org/>
100% accessible validated (X)HTML - Blog: <http://www.vinc17.org/blog/>
Work: CR INRIA - computer arithmetic / Arenaire project (LIP, ENS-Lyon)

Avatar
Stephane Chazelas
On Mon, 03 Dec 2007 17:28:43 +0100, mpg wrote:
Soient deux répertoires A et B (dans mon home, mettons), C un
sous-répertoire de A, et D un lien symbolique placé dans B et pointant vers
C. Si, depuis B, je fais 'cd D', et que j'affiche PWD,
j'obtiens /home/moi/B/D. Si je fais 'cd ..' je reviens dans B. Si par
contre, je choisis un fichier F de C, et que, au moment où mon PWD
est /home/moi/B/D, je fais 'cp F ..', F se retrouve dans A.

Je trouve ça assez troublant : est-ce que c'est un comportement normal ?
Quelle est la logique derrière ça ?
[...]


C'est une fonctionalité douteuse introduite par ksh. Qui a ete
standardisee depuis dans le sh POSIX et donc dans les
Bourne like shells recents.

C'est une idee qui vient probablement du $cwd de csh. Le $cwd de
csh tout comme le $PWD de ksh ne contiennent pas le chemin
courant tel que connu par le systeme et retourné par getcwd(2)
ou /bin/pwd (appelons-le chemin courant physique). A la place,
$cwd/$PWD est construit dynamiquement a partir des arguments
passés a la commande "cd" (appelons celui-ci chemin courant
logique) (sous csh, il y a une option pour changer ce
comportement)

Mais la ou ksh va plus loin que csh est qu'il introduit deux
modes de fonctionnement differents aux commandes "cd" et "pwd"
(pwd devient d'ailleurs une commande built-in pour cela). Un
mode "physique" avec l'option -P et un mode logique avec
l'option -L. L'erreur de ksh est qu'il a fait de ce dernier le
comportement par defaut, meme quand le shell n'est pas
interactif.

Dans ce mode, cd et pwd manipulent le chemin logique (il faut
bien se rappeler que le chemin logique c'est qu'un concept
interne au shell, le systeme et les autres commandes ne sont pas
au courant) et cd traite ".." differement. Faire un "cd .." ne
fait pas chdir("..") mais fait un chdir(`basename -- "$PWD"`).

Ce qui fait que:

cd ..
vi a

n'est pas la meme chose que:

vi ../a

ksh met $PWD dans l'environnement. Ce qui fait que si on lance
un autre ksh comme un script ksh, ce deuxieme ksh va heriter son
$PWD de la. POSIX interdit ce comportement. Malheureusement,
aucun shell soit-disant POSIX a ma connaissance n'est conforme
par rapport a ca.

Ca veut dire que si j'ecris un script qui fait
#! /usr/bin/ksh -
cd -- "$(dirname -- "${1?}")" || exit
vi -- "$(basemane -- "$1")"

Et que je fais:

~$ cd /tmp
/tmp$ ln -s . here
/tmp$ env PWD=/tmp/here/here/here mon-script ../etc/motd

Le script va faire:

chdir("/tmp/here/here/etc")

et echouer.

C'est pour ca que dans les scripts POSIX ou ksh... il ne faut
jamais utiliser "cd" (ou pwd) sans l'option "-P"

Note que ce $PWD commence a se propager au delà de ksh et des
shells, la GNU libc par exemple a une fonction
get_current_dir_name(3) qui peut retourner la variable
d'environnement $PWD, donc il n'est pas exclu que certaines
commandes GNU l'utilisent...

--
Stephane

Avatar
Olivier Miakinen
Bonjour,

J'ai une petite question connexe.


[...]

C'est une idee qui vient probablement du $cwd de csh. Le $cwd de
csh tout comme le $PWD de ksh ne contiennent pas le chemin
courant tel que connu par le systeme et retourné par getcwd(2)
ou /bin/pwd (appelons-le chemin courant physique). A la place,
$cwd/$PWD est construit dynamiquement a partir des arguments
passés a la commande "cd" (appelons celui-ci chemin courant
logique) (sous csh, il y a une option pour changer ce
comportement)

[...]


Cette distinction entre chemin logique et chemin physique, ou plus
exactement le fait même que l'on puisse parler de chemin physique,
vient du fait que l'on ne peut avoir que des liens symboliques entre
répertoires.

Cela veut donc dire qu'il n'existe plus aucun Unix ou Unix-like qui
accepte de faire des « hard links » entre répertoires ? Depuis combien
de temps cette possibilité a-t-elle disparu ? Et vers où pointait le
« .. » à l'époque ? J'ai déjà vu ce genre d'Unix, mais si j'ai testé
le « cd .. » je ne me rappelle pas ce que faisait « vi ../truc ».

Avatar
Stephane Chazelas
On Tue, 04 Dec 2007 10:10:59 +0100, Olivier Miakinen wrote:
[...]
Cela veut donc dire qu'il n'existe plus aucun Unix ou Unix-like qui
accepte de faire des « hard links » entre répertoires ? Depuis combien
de temps cette possibilité a-t-elle disparu ? Et vers où pointait le
« .. » à l'époque ? J'ai déjà vu ce genre d'Unix, mais si j'ai testé
le « cd .. » je ne me rappelle pas ce que faisait « vi ../truc ».
[...]


Deja avec Unix V3 (1973), on ne pouvait pas faire de lien vers
des repertoires avec la commande ln, meme si apparemment le
systeme (link(2)) le permettait aux super-users uniquement.

Voir
http://minnie.tuhs.org/UnixTree/V3/usr/man

Toujours d'apres le manuel, c'etait encore autorisé chez Solaris
8.

Le manuel de getcwd() ne precise pas comment est calculee la
valeur.

Mais chez Solaris, getcwd() n'est pas un appel systeme, en fait,
il cherche dans le contenu de "../" la premiere entree qui a le
meme inum que "./" et repete l'operation pour ../../, ../../../
etc jusqu'a trouver "/", ce qui lui permet de contruire un
chemin.

Faire un lien vers un directory ne fait qu'ajouter une entree
dans un directory, ca n'affecte pas de "." ou de "..".

Si tu fais
mkdir /tmp/foo

Ca cree 1 inode A qui est referencé dans "/tmp/", et dans le
directory d'inode A, ya une entree pour "." qui pointe sur A et
une entree pour ".." qui pointe vers l'inode de "/tmp/".

Si tu fais:

sudo link /tmp/foo /tmp/bar/baz

Tu ne fais que rajouter une entree "baz" dans le directory
"/tmp/bar/" qui pointe vers A.

cd -P /tmp/bar/baz/..

/tmp/bar/baz/.. est le meme inode que /tmp/foo/.., donc, ca
revient a faire cd -P /tmp

--
Stephane

Avatar
Cyrille Lefevre
C'est une fonctionalité douteuse introduite par ksh. Qui a ete
standardisee depuis dans le sh POSIX et donc dans les
Bourne like shells recents.

C'est une idee qui vient probablement du $cwd de csh. Le $cwd de
csh tout comme le $PWD de ksh ne contiennent pas le chemin
courant tel que connu par le systeme et retourné par getcwd(2)
ou /bin/pwd (appelons-le chemin courant physique). A la place,
$cwd/$PWD est construit dynamiquement a partir des arguments
passés a la commande "cd" (appelons celui-ci chemin courant
logique) (sous csh, il y a une option pour changer ce
comportement)


s/csh/tcsh/ :)

peut-être que NFS y est pour qqc aussi ? surtout du temps ou il y
avait encore les /tmp_mnt. depuis, vive l'autofs en remplacement
de l'automountd (si je me souviens bien :) car faire un cd relatif
alors que le point de montage s'est barré entre temps pour cause
de non utilisation récente, pas glop. alternative, cd ${PWD#/tmp_mnt}
permettait de contourner ce petit inconvénient...

Mais la ou ksh va plus loin que csh est qu'il introduit deux
modes de fonctionnement differents aux commandes "cd" et "pwd"
(pwd devient d'ailleurs une commande built-in pour cela). Un
mode "physique" avec l'option -P et un mode logique avec
l'option -L. L'erreur de ksh est qu'il a fait de ce dernier le
comportement par defaut, meme quand le shell n'est pas
interactif.


est-ce vraiment une erreur (inconvénient) ou un avantage ?
pour ma part, c'était vraiment très ennuyeux d'être obligé
de faire cd /path/to/ancient/chemin plutôt que de simplement
faire cd .. lorsque l'on traverse un lien symbolique.
surtout avec les anciens csh/tcsh qui ne supportait pas encore
la variable symlinks.

pour autant, rien n'empêche de faire un alias cd='cd -P' pour
les nostalgiques :)

ksh met $PWD dans l'environnement. Ce qui fait que si on lance
un autre ksh comme un script ksh, ce deuxieme ksh va heriter son
$PWD de la. POSIX interdit ce comportement. Malheureusement,
aucun shell soit-disant POSIX a ma connaissance n'est conforme
par rapport a ca.


ou as-tu vu cette interdiction au demeurant très pratique ?

C'est pour ca que dans les scripts POSIX ou ksh... il ne faut
jamais utiliser "cd" (ou pwd) sans l'option "-P"


faut voir, tout dépend de ce que tu veux faire !

Cordialement,

Cyrille Lefevre.
--
mailto:Cyrille.Lefevre-news%
supprimer "%nospam% et ".invalid" pour me repondre.
remove "%nospam" and ".invalid" to answer me.

Avatar
Stephane Chazelas
On Tue, 04 Dec 2007 12:11:17 +0100, Cyrille Lefevre wrote:
C'est une fonctionalité douteuse introduite par ksh. Qui a ete
standardisee depuis dans le sh POSIX et donc dans les
Bourne like shells recents.

C'est une idee qui vient probablement du $cwd de csh. Le $cwd de
csh tout comme le $PWD de ksh ne contiennent pas le chemin
courant tel que connu par le systeme et retourné par getcwd(2)
ou /bin/pwd (appelons-le chemin courant physique). A la place,
$cwd/$PWD est construit dynamiquement a partir des arguments
passés a la commande "cd" (appelons celui-ci chemin courant
logique) (sous csh, il y a une option pour changer ce
comportement)


s/csh/tcsh/ :)


Au temps pour moi (pour l'option "hardpaths").

[...]
Mais la ou ksh va plus loin que csh est qu'il introduit deux
modes de fonctionnement differents aux commandes "cd" et "pwd"
(pwd devient d'ailleurs une commande built-in pour cela). Un
mode "physique" avec l'option -P et un mode logique avec
l'option -L. L'erreur de ksh est qu'il a fait de ce dernier le
comportement par defaut, meme quand le shell n'est pas
interactif.


est-ce vraiment une erreur (inconvénient) ou un avantage ?
pour ma part, c'était vraiment très ennuyeux d'être obligé
de faire cd /path/to/ancient/chemin plutôt que de simplement
faire cd .. lorsque l'on traverse un lien symbolique.
surtout avec les anciens csh/tcsh qui ne supportait pas encore
la variable symlinks.

pour autant, rien n'empêche de faire un alias cd='cd -P' pour
les nostalgiques :)
[...]


Il aurait ete plus logique, au moins pour backward compatibilité
et pour que les scripts continuent a marcher correctement, de
faire cd -P par defaut et de donner l'option de faire "alias
cdÍ -L" a l'utilisateur interactif.

Et il y a la dirstack pour revenir ou on etait avant (cd -, cd
+12, pushd/popd... tout ca avec completion sous zsh au moins)

ksh met $PWD dans l'environnement. Ce qui fait que si on lance
un autre ksh comme un script ksh, ce deuxieme ksh va heriter son
$PWD de la. POSIX interdit ce comportement. Malheureusement,
aucun shell soit-disant POSIX a ma connaissance n'est conforme
par rapport a ca.


ou as-tu vu cette interdiction au demeurant très pratique ?


PWD
Set by the shell to be an absolute pathname of the
current working directory, containing no components
of type symbolic link, no components that are dot,
and no components that are dot-dot when the shell is
initialized. If an application sets or unsets the
value of PWD , the behaviors of the cd and pwd
utilities are unspecified.

http://www.opengroup.org/onlinepubs/009695399/utilities/xcu_chap02.html#tag_02_05_03

Voir aussi
http://bugs.opensolaris.org/view_bug.do?bug_idG63915

C'est pour ca que dans les scripts POSIX ou ksh... il ne faut
jamais utiliser "cd" (ou pwd) sans l'option "-P"


faut voir, tout dépend de ce que tu veux faire !
[...]


Donne un exemple de script ou ca fait du sens d'utiliser "cd",
c.a.d "cd -L"...

--
Stephane


Avatar
Olivier Miakinen

Deja avec Unix V3 (1973), on ne pouvait pas faire de lien vers
des repertoires avec la commande ln, meme si apparemment le
systeme (link(2)) le permettait aux super-users uniquement.

Voir
http://minnie.tuhs.org/UnixTree/V3/usr/man


Exact. Idem avec Unix V7 :
http://minnie.tuhs.org/UnixTree/V7/usr/man/

Pour ma part, j'avais constaté ça aux alentours de l'année 1988 mais je
ne sais plus si c'était sur un DPX/2 (je crois qu'il s'agissait alors
d'un System V.2 ou V.3) ou sur l'implémentation qu'on en faisait comme
application de GCOS7 (mélange de System V.qqch, et de BSD 4.2 ou 4.3
pour les sockets). Mes souvenirs sont très flous, d'autant que j'étais
encore un petit débutant tout juste sorti de l'école. Cela pouvait
aussi bien être sur un Sun 3 ou un Sun 4 d'ailleurs, car on en avait
quelques uns.

[ suite des explications ]


Je n'ai pas encore tout compris : je relirai à tête reposée cet
après-midi ou ce soir. Mais je te remercie déjà pour ta réponse.

Avatar
mpg
Stephane Chazelas wrote:

On Mon, 03 Dec 2007 17:28:43 +0100, mpg wrote:
Quelle est la logique derrière ça ?
[...]


[...]

Dans ce mode, cd et pwd manipulent le chemin logique (il faut
bien se rappeler que le chemin logique c'est qu'un concept
interne au shell, le systeme et les autres commandes ne sont pas
au courant) et cd traite ".." differement. Faire un "cd .." ne
fait pas chdir("..") mais fait un chdir(`basename -- "$PWD"`).

D'accord. Je comprends maintenant la logique de la chose. Je n'avais pas

saisi auparavant que le « chemin logique » était un truc interne au shell.
Ça éclaire tout en effet. D'ailleurs j'avais remarqué que zsh (au moins)
est en quelque sorte conscient de ce phénomène, car si on fait
cd ../<tab><tab>
il ne présente pas la même liste qu'avec par exemple
vim ../<tab><tab>

Merci pour cette explication très claire.

Je crois que je vais légèrement changer mes habitudes (et/ou la config de
mon shell) et être plus prudent avec les liens symboliques et ce que
m'affiche mon shell comme $PWD...

Manuel.


Avatar
Paul Gaborit
À (at) Tue, 04 Dec 2007 12:11:17 +0100,
Cyrille Lefevre <cyrille.lefevre-news% écrivait (wrote):
peut-être que NFS y est pour qqc aussi ? surtout du temps ou il y
avait encore les /tmp_mnt.


C'était vrai avec les vieux automonteurs qui passaient par des points
de montages non déplaceables (tous dans '/tmp_mnt' par exemple). Mais
ça n'a eu qu'un temps. Et puis, on s'y faisait : je me souviens qu'on
définissait des règles de complétions tres sioux avec 'tcsh' pour
permettre de bien les utiliser. On avait ausi une version spécifique
de 'mkdepend' pour nettoyer les path qui contenaient du /tmp_mnt...

Mais, c'est vieux tout ça, et ça ne justifie sûrement pas ce
comportement (surtout par défaut).

--
Paul Gaborit - <http://perso.enstimac.fr/~gaborit/>

1 2