
Я создал символическую ссылку с абсолютным путем к каталогу (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/B
directory, а не aliased /tmp/A/Blink
. Чтобы сделать это, вы можете использовать следующую функцию вместо cd
(которую вы можете поместить в свой .bashrc)
lcd() { cd $(readlink -f "$1"); }
lcd
, конечно, работает как для обычных, так и для символически-связанных каталогов.
Примечание: readlink -f
действует на конечную цель ссылки (когда ссылки соединены последовательно)..