символическая ссылка на каталог и относительный путь

символическая ссылка на каталог и относительный путь

Я создал символическую ссылку с абсолютным путем к каталогу (Blink) и имею, например, следующее дерево:

$ 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

затем я иду в /tmp/A и меняю каталог на Blink:

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

cd ..возвращает меня к , /tmp/A но если я введу, например, ls ../fooя получу ошибку:

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

Встроенная команда cd определяет путь по мере необходимости, но внешняя команда ls рассматривает .. как файл верхнего уровня /tmp/B и поэтому не может найти foo.

В чем тут проблема? Можно ли получить файл foo из /tmp/A/Blink по относительному пути, например ../foo?

решение1

Оболочка сохраняет текущий рабочий каталог в $PWD. Это то, что используется для встроенных функций оболочки cdи pwd, и она обрабатывает символические ссылки как обычные каталоги, как вы видели. Иногда это полезно, иногда нет.

Найти настоящий каталог можно с помощью pwd(введите help pwdдля получения более подробной информации):

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

Аналогично, cdесть вариант -P(опять же, help cdваш друг):

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

Наконец, вы можете вообще отключить эту «функцию»:

$ set -P
$ cd /tmp/A/Blink
$ pwd
/tmp/B

решение2

Я не думаю, что вы можете это сделать. В наши дни оболочки отслеживают, как они оказались там, где они есть, они отслеживают текущий рабочий каталог по имени, а не просто полагаются на файловую систему и ОС, чтобы сохранить его. Это означает, что встроенный cdможет "создать резервную копию" символической ссылки, а не просто следовать цепочкам ".." напрямую.

Но когда вы запускаете ls ../foo, lsне знает, что оболочка попала в каталог, следуя символическим ссылкам. lsвыполнит a stat()на "../foo". Часть ".." берется из текущего каталога, в котором есть только одна запись ".." для его родителя. Вся эта штука с символическими ссылками не меняет того, как каталоги имеют одну запись ".." и одну запись ".." Символические ссылки позволяют ядру вставлять дополнительный уровень косвенности в пути к файлам. Когда вы передаете "../whatever" в open()или stat(), ядро ​​просто использует текущий рабочий каталог процесса, выполняющего вызов, чтобы выяснить, какой отдельный каталог назван "..".

решение3

Брюс и амс дали прекрасные ответы, объясняющие поведение, стоящее за этим. Но чтобы на самом деле сделать то, о чем ls ../fooвы спрашивали, вы могли бы пойти с чем-то вроде

ls $(dirname $PWD)/foo

решение4

Вы не можете этого сделать, потому что/tmp/A/Blink являетсяна самом деле /tmp/B. Так что, ls ../A/fooработает.

Вместо этого вам может быть полезно иметь возможностьCDкнастоящий /tmp/Bdirectory, а не aliased /tmp/A/Blink. Чтобы сделать это, вы можете использовать следующую функцию вместо cd(которую вы можете поместить в свой .bashrc)

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

lcd, конечно, работает как для обычных, так и для символически-связанных каталогов.
Примечание: readlink -fдействует на конечную цель ссылки (когда ссылки соединены последовательно)..

Связанный контент