dowiązanie symboliczne do katalogu i ścieżki względnej

15

Utworzyłem dowiązanie symboliczne z bezwzględną ścieżką do katalogu (Blink) i mam na przykład następujące drzewo:

$ 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

następnie przechodzę do / tmp / A i zmieniam katalog na Blink:

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

cd ..zwraca mnie, /tmp/A ale jeśli napiszę na przykład ls ../foo, otrzymam błąd:

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

wbudowana komenda cd rozpoznaje ścieżkę w razie potrzeby, ale zewnętrzny ls uważa .. za wyższy poziom / tmp / B i dlatego nie może znaleźć foo.

Jaki jest tutaj problem? Czy mogę pobrać plik foo z / tmp / A / Blink za pomocą ścieżki względnej, takiej jak ../foo?

użytkownik478681
źródło
To samo pytanie jest cross-pisał na superuser
Peter.O

Odpowiedzi:

13

Nie sądzę, że możesz to zrobić. Obecnie powłoki śledzą, w jaki sposób dotarły na miejsce, śledzą bieżący katalog roboczy według nazwy, a nie tylko polegają na systemie plików i systemie operacyjnym, aby go zachować. Oznacza to, że wbudowane narzędzie cdmoże „cofnąć” link symboliczny, zamiast bezpośrednio podążać za łańcuchami „..”.

Ale po uruchomieniu ls ../foo, lsnie jest świadoma, że powłoka dostał się do katalogu, wykonując dowiązania symboliczne. lszrobi a stat()na „../foo”. Część „..” pochodzi z bieżącego katalogu, który ma tylko jeden wpis „..” dla swojego rodzica. Cała dowiązanie symboliczne nie zmienia sposobu, w jaki katalogi mają pojedyncze „.” i pojedynczy wpis „..”. Dowiązania symboliczne pozwalają jądrze wstawić dodatkową warstwę pośrednią do ścieżek plików. Kiedy przekazujesz „../whokolwiek” do open()lub stat(), jądro po prostu używa bieżącego katalogu roboczego procesu, wykonując wywołanie, aby dowiedzieć się, który pojedynczy katalog ma nazwę „..”.

Bruce Ediger
źródło
17

Powłoka przechowuje bieżący katalog roboczy w $PWD. To, co jest wykorzystywane do poleceń wbudowanych cdi pwd, i traktuje dowiązania jako normalnych katalogach, jak widzieliście. Czasami jest to pomocne, a czasem nie.

Możesz znaleźć prawdziwy katalog, używając pwd(wpisz help pwdwięcej szczegółów):

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

Podobnie cdma opcję -P(znowu, help cdjest twoim przyjacielem):

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

Na koniec możesz całkowicie wyłączyć „funkcję”:

$ set -P
$ cd /tmp/A/Blink
$ pwd
/tmp/B
ams
źródło
Dzięki, wiem o ustawieniu funkcji -P, ale byłem zdezorientowany zachowaniem polecenia ls ...
user478681,
Jak powiedziałem, set -Pzachowanie i ls zaczyna mieć sens. :)
AMS
2

Bruce i ams udzielili pięknych odpowiedzi, wyjaśniając zachowanie z tyłu. Ale żeby faktycznie zrobić to, o ls ../fooco prosiłeś, możesz pójść z czymś takim

ls $(dirname $PWD)/foo
Antti Vikman
źródło
1

Nie możesz tego zrobić, bo /tmp/A/Blink tak naprawdę jest/tmp/B . Więc ls ../A/foodziała.

Zamiast tego możesz uznać za przydatne możliwość cd do prawdziwego /tmp/B katalogu zamiast do aliasu /tmp/A/Blink. Aby to zrobić, możesz użyć następującej funkcji zamiast cd(którą możesz umieścić w swoim .bashrc)

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

lcd, oczywiście, działa zarówno dla normalnych, jak i symbolicznych katalogów.
Uwaga: readlink -fdziała na ostateczny cel linku (gdy linki są połączone łańcuchowo) ..

Peter.O
źródło
1
cd -Pwydaje się prostsze.
jw013
@ jw013: Masz rację; to jest. Nie wiedziałem o tym .. dzięki ..
Peter.O