tautan simbolik ke direktori dan jalur relatif

15

Saya telah membuat symlink dengan path absolut ke direktori (Blink) dan memiliki pohon contoh sebagai berikut:

$ 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

kemudian saya pergi ke / tmp / A dan mengubah direktori ke Blink:

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

cd ..mengembalikan saya ke /tmp/A tetapi jika saya mengetik misalnya ls ../foosaya akan mendapat kesalahan:

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

perintah cd builtin menyelesaikan path sesuai kebutuhan, tetapi ls eksternal menganggap .. sebagai up-level / tmp / B dan karenanya tidak dapat menemukan foo.

Apa masalah yang terjadi di sini? Bisakah saya mendapatkan file foo dari / tmp / A / Blink dengan jalur relatif seperti ../foo?

pengguna478681
sumber
Pertanyaan yang sama juga diposting di SuperUser
Peter.O

Jawaban:

13

Saya tidak berpikir Anda bisa melakukan ini. Shell sekarang melacak bagaimana mereka sampai di mana mereka berada, mereka melacak direktori kerja saat ini dengan nama, bukan hanya mengandalkan sistem file dan OS untuk menyimpannya. Itu berarti built-in cddapat "mencadangkan" tautan simbolik, daripada hanya mengikuti rantai ".." secara langsung.

Tetapi ketika Anda menjalankan ls ../foo, lstidak menyadari bahwa shell masuk ke direktori dengan mengikuti tautan simbolik. lsakan melakukan stat()pada "../foo". Bagian ".." berasal dari direktori saat ini, yang hanya memiliki satu entri ".." untuk induknya. Keseluruhan tautan simbolik tidak mengubah cara direktori memiliki satu "." dan satu entri "..". Tautan simbolik membiarkan kernel menyisipkan lapisan tipuan tambahan ke dalam jalur file. Ketika Anda meneruskan "../wh Apapun" ke open()atau stat(), kernel hanya menggunakan direktori kerja saat ini dari proses melakukan panggilan untuk mencari tahu direktori tunggal mana yang dinamai dengan "..".

Bruce Ediger
sumber
17

Shell menyimpan direktori kerja saat ini di $PWD. Itulah yang digunakan untuk shell builtin cddan pwd, dan memperlakukan symlink sebagai direktori normal, seperti yang Anda lihat. Terkadang ini membantu, kadang tidak.

Anda dapat menemukan direktori nyata menggunakan pwd(ketik help pwduntuk lebih jelasnya):

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

Demikian juga, cdmemiliki opsi -P(sekali lagi, help cdadalah teman Anda):

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

Akhirnya, Anda dapat mematikan "fitur" sama sekali:

$ set -P
$ cd /tmp/A/Blink
$ pwd
/tmp/B
am
sumber
Terima kasih, saya mengetahui tentang set -P fitur, tetapi bingung dengan perilaku perintah ls ...
user478681
Seperti saya katakan, penggunaan set -Pdan perilaku mulai masuk akal. :)
ams
2

Bruce dan saya memberikan jawaban yang indah menjelaskan perilaku di belakang. Tetapi untuk benar-benar melakukan apa yang ls ../fooAnda minta, Anda bisa pergi dengan sesuatu seperti

ls $(dirname $PWD)/foo
Antti Vikman
sumber
1

Anda tidak bisa melakukannya, karena /tmp/A/Blink ini sebenarnya /tmp/B. Begitu,ls ../A/foo berhasil.

Alih-alih, Anda mungkin merasa berguna untuk dapat melakukan cd ke direktori yang sebenarnya /tmp/B , alih-alih alias /tmp/A/Blink. Untuk melakukan itu, Anda dapat menggunakan fungsi berikut alih-alih cd(yang dapat Anda masukkan ke .bashrc)

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

lcd, tentu saja, berfungsi untuk direktori normal dan simbolik terkait.
Catatan: readlink -fbertindak atas target akhir tautan (saat tautan diikat daisy) ..

Peter.O
sumber
1
cd -Psepertinya lebih sederhana.
jw013
@ jw013: Anda benar; ini. Saya tidak menyadarinya .. terima kasih ..
Peter.O