символічне посилання на каталог і відносний шлях


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?


Те ж питання крос-розміщений на суперкористувача
Peter.O

Відповіді:


13

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

Але при запуску ls ../foo, lsне знає , що оболонка потрапила в каталог, слідуючи символічні посилання. lsбуде робити stat()на "../foo". Частина ".." походить з поточного каталогу, в якому є лише один запис ".." для його батьків. Вся символічна посилання не змінює те, як каталоги мають єдине "". і один запис "..". Символічні посилання дозволяють ядру вставити додатковий шар непрямості у файлові шляхи. Коли ви передаєте "../wever" до 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

Як я вже говорив, використання set -Pта поведінка, починає мати сенс. :)
ams

2

Брюс і Емс дали прекрасні відповіді, пояснюючи поведінку позаду. Але насправді робити те, про що ls ../fooви просили, ви можете піти з чимось подібним

ls $(dirname $PWD)/foo

1

Ви не можете цього зробити, бо /tmp/A/Blink це насправді /tmp/B. Отже, ls ../A/fooпрацює.

Натомість ви можете вважати корисним вміння CD до реального /tmp/B каталогу, а не дозволеного /tmp/A/Blink. Для цього ви можете використовувати наступну функцію замість cd(яку ви можете помістити у свій .bashrc)

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

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


1
cd -Pздається простішим.
jw013

@ jw013: Ти маєш рацію; Це є. Я не знав про це .. дякую ..
Пітер.О
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.