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

15

Я создал символическую ссылку с абсолютным путем к каталогу (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?

user478681
источник
Тот же вопрос перекрестно опубликован на SuperUser
Peter.O

Ответы:

13

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

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

Брюс Эдигер
источник
17

Оболочка хранит текущий рабочий каталог в $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
военно-картографическая служба
источник
Спасибо, я знаю о функции set -P, но был сбит с толку поведением команды ls ...
user478681
Как я уже сказал, использование use set -Pи ls начинает иметь смысл. :)
Ams
2

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

ls $(dirname $PWD)/foo
Антти Викман
источник
1

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

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

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

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

Peter.O
источник
1
cd -Pкажется проще.
jw013
@ jw013: Вы правы; это. Я не знал об этом .. спасибо ..
Peter.O