Dlaczego muszę wypisywać cd z usuniętego katalogu?

19

Na moim serwerze mam strukturę katalogów wyglądającą mniej więcej tak:

/myproject/code

Zwykle mam połączenie ssh z serwerem i „stand” w tym katalogu:

root@machine:/myproject/code#

Kiedy wdrażam nową wersję mojego kodu, katalog kodu jest usuwany, więc pozostaję z:

root@machine:/myproject/code# ./run
-bash: ./run: No such file or directory

I jedynym rozwiązaniem, jakie znalazłem, jest wyjście na dysk CD i ponowne:

root@machine:/myproject/code# cd ../code
root@machine:/myproject/code# ./run
Running...

Czy mogę tego uniknąć? To trochę dziwne zachowanie. Jeśli masz dobre wyjaśnienie, dlaczego tak się dzieje, byłbym wdzięczny.

Markus Johansson
źródło
5
Czy myślałeś o usunięciu plików z katalogu kodu, a nie samego katalogu kodu?
StrongBad
9
Mylisz się, że nowo utworzony katalog runjest taki sam jak stary katalog. Ma tylko tę samą nazwę i katalog nadrzędny. Porównaj to z niszczeniem starego samochodu i kupowaniem nowego samochodu dokładnie tego samego koloru i modelu: Nie chcesz siedzieć w rozdrobnionym samochodzie i mam nadzieję, że skończysz na nowym bez szwanku, prawda?
Anthon
2
Anthon: Zakładam, że ścieżka identyfikuje katalog. Dla mnie „cd ../code” to noop. Jestem bardzo zainteresowany słyszeniem, dlaczego tak nie jest.
Markus Johansson
2
@MarkusJohansson cd ../codenie jest noop. ..jest skrótem do elementu nadrzędnego ścieżki, którą masz lub którą posiadałeś. Jeśli bieżący katalog zostanie usunięty, ścieżka nadrzędna może nadal istnieć, aw tym przypadku można ją uzyskać, oceniając ... W tym katalogu odbywa się wyszukiwanie katalogu o nazwie „kod”.
Anthon
2
@MarkusJohansson Zamiast usuwać i tarować kod, zdecydowanie zaleciłbym użycie dowolnego dostępnego narzędzia kontroli wersji. Znacznie łatwiejsze udostępnianie aktualizacji (po prostu push lub pull) i mniej opcji przypadkowego usunięcia niewłaściwych plików. Domyślnie zachowujesz starszą wersję.
Bernhard

Odpowiedzi:

26

Dla mnie „cd ../code” to noop. Jestem bardzo zainteresowany słyszeniem, dlaczego tak nie jest.

Ponieważ pliki i katalogi są zasadniczo i- węzłami systemu plików , a nie nazwami - być może jest to szczegół implementacji specyficzny dla typu systemu plików, ale dotyczy to wszystkich systemów ext, więc pozostanę przy tym.

Po utworzeniu nowego katalogu codejest on powiązany z nowym i-węzłem i właśnie tam jest. Nie ma zapisanych wcześniej usuniętych plików i katalogów, więc nie ma sposobu, aby system mógł sprawdzić, jaki był zajęty i-węzeł i być może przetasować rzeczy, aby znów było tak samo; taki system szybko stałby się niewykonalny, a w każdym razie prawdopodobnie nie ma gwarancji, że wrócisz tam ponownie - byłoby to trochę niepożądane, ponieważ oznacza to, że możesz przypadkowo skończyć gdzie indziej, jeśli katalog zostanie utworzony który bierze twój (obecnie nieużywany) i-węzeł.

Nie jestem pewien, czy ta ostatnia możliwość istnieje, czy też i-węzeł usuniętego katalogu aktualnie przypisanego do bieżącego katalogu roboczego jest śledzony, aby nic nie zostało do niego przypisane na czas trwania itp.

Złotowłosa
źródło
3
To jest prawdziwa odpowiedź tutaj.
karan.dodia,
14

Twoja powłoka nie zawsze wykonuje cdścieżkę do ścieżki, w której znajdowała się podczas ostatniego polecenia, przed wykonaniem następnego polecenia.

Usunąłeś bieżący katalog i utworzyłeś katalog o tej samej nazwie, który nie jest tym samym katalogiem, tylko czymś o tej samej nazwie / ścieżce.

Przeglądarki plików, takie jak Nautilus i Windows Explorer, zwykle „przechodzą” do drzewa katalogów, jeśli katalog zostanie usunięty z lokalnego systemu plików. Jednak nie zawsze tak jest w przypadku sieciowych systemów plików, w takim przypadku czasami usunięcie nie jest zauważane, a ponowne pojawienie się może spowodować, że skończysz w nowym katalogu.

Powłoka mogłaby cdwejść do bieżącego katalogu przed wykonaniem następnego polecenia, nie jestem świadomy żadnego takiego działania (lub można to skonfigurować).

Anthon
źródło
Na ilustracji - teoretycznie mógłby istnieć system plików, w którym stary, usunięty (lub raczej niepowiązany) katalog nadal istnieje i jest czytelny, podczas gdy nowy jest już w użyciu. W praktyce nie byłoby to przydatne w przypadku katalogów, ale w przypadku plików jest to dość powszechne.
Volker Siegel,
4

W większości systemów podobnych do UNIX „bieżący katalog” procesu jest przechowywany w jądrze jako deskryptor pliku wskazujący ten katalog. Jądro tak naprawdę nie przechowuje ścieżki bieżącego katalogu: informacje są śledzone przez twoją powłokę.

Obiekt systemu plików (plik lub katalog) zostaje zniszczony na dobre tylko wtedy, gdy znikają wszystkie łącza do systemu plików i nie ma deskryptorów plików wskazujących na ten obiekt.

Tak więc, jeśli katalog zostanie usunięty, podczas gdy proces nadal utrzymuje go jako bieżący katalog roboczy, proces nie cwdpozwoli na jego usunięcie. Łącza do systemu plików, które zakotwiczą katalog (jego wpis w katalogu nadrzędnym i cała jego zawartość) znikną, ale sam katalog będzie istniał jako rodzaj „zombie”. W międzyczasie możesz utworzyć zupełnie nowy katalog w tym samym miejscu, co stary, który jest zupełnie innym obiektem systemu plików, ale ma tę samą ścieżkę.

Tak więc, kiedy to robisz cd ../code(lub w wielu powłokach cd .), faktycznie przechodzisz przez hierarchię systemu plików i przechodzisz do nowego katalogu, który znajduje się pod starym adresem.

Analogicznie usunięcie katalogu byłoby jak wymuszone przeniesienie domu na wysypisko śmieci (zerwanie powiązań z poprzednim adresem). Jeśli nadal cwdbyłby tam ktoś (używając go jako swojego ), musieliby wyjść, zanim dom zostanie zrównany z ziemią. W międzyczasie pod starym adresem można wybudować nowy dom.

nneonneo
źródło
0

@Anthon wyjaśnił powody, dla których tak się dzieje
Jako rozwiązanie możesz użyć aliasu , na przykład:

alias 1234='PROJECT=`pwd`; cd $PROJECT ; ./run'

aliasy bash są wpisane w ~ / .bashrc

MolbOrg
źródło
0

Potwierdzanie Bieżący katalog roboczy jest oparty na numerze i-węzła, a nie na tym, czego szukałeś, aby się tam dostać. Ponieważ używasz bash, możesz użyć $ PWD w następujący sposób, aby cd do nowego katalogu o tej samej nazwie:

cd $ PWD

Aby to zilustrować, podjąłem atrapę polecenia wdrażania:

set -x
cd ~/tmp
rm -rf code
mkdir code
echo echo hello from $* > code/run
chmod +x code/run

Utworzono pierwsze wdrożenie, cd'd do kodowania, a następnie sprawdzono zawartość za pomocą, ls -laiaby zobaczyć i-węzły:

ianh@abe:~/tmp$ ./,deploy first
++ cd /home/ianh/tmp
++ rm -rf code
++ mkdir code
++ echo echo hello from first
++ chmod +x code/run
ianh@abe:~/tmp$ cd code
ianh@abe:~/tmp/code$ ls -lai
total 12
22945913 drwxr-xr-x  2 ianh ianh 4096 Apr  9 23:12 .
22937618 drwxrwxr-x 14 ianh ianh 4096 Apr  9 23:12 ..
22939455 -rwxr-xr-x  1 ianh ianh   22 Apr  9 23:12 run

Teraz uruchom drugie wdrożenie

ianh@abe:~/tmp/code$ ../,deploy 2nd
++ cd /home/ianh/tmp
++ rm -rf code
++ mkdir code
++ echo echo hello from 2nd
++ chmod +x code/run

I sprawdź zawartość katalogu ... teraz nic nie ma w katalogu! nawet nie '.' i '..'! Z tego widać, że bash nie używa wpisu katalogu „..”, gdy działasz, cd ..ponieważ „..” już nie istnieje - przypuszczam, że jest to część jego obsługi $ PWD. Niektóre inne / starsze powłoki nie radzą sobie cd ..w tej sytuacji, musisz najpierw cd do absolutnej ścieżki.

ianh@abe:~/tmp/code$ ls -lai
total 0

Cd do $PWDi spróbuj ponownie:

ianh@abe:~/tmp/code$ cd $PWD
ianh@abe:~/tmp/code$ ls -lai
total 12
22945914 drwxr-xr-x  2 ianh ianh 4096 Apr  9 23:12 .
22937618 drwxrwxr-x 14 ianh ianh 4096 Apr  9 23:12 ..
22939455 -rwxr-xr-x  1 ianh ianh   20 Apr  9 23:12 run
ianh@abe:~/tmp/code$ ./run
hello from 2nd

Zauważ, jak zmienił się i-węzeł dla bieżącego katalogu (.)?

Jeśli skrypt wdrażania przeniósł stary katalog na inną nazwę, np. mv code code.$$W powyższym skrypcie wdrażania, ./rundziałałby, ale dopóki go nie użyjesz cd $PWD, uruchomisz stary kod, a nie nowy.

ianh@abe:~/tmp/code$ ./run
hello from 2nd
ianh@abe:~/tmp/code$ ../,deploy 3rd
++ cd /home/ianh/tmp
++ '[' -d code ']'
++ mv code code.9629
++ mkdir code
++ echo echo hello from 3rd
++ chmod +x code/run
ianh@abe:~/tmp/code$ ./run
hello from 2nd
ianh@abe:~/tmp/code$ cd $PWD
ianh@abe:~/tmp/code$ ./run
hello from 3rd

Wdrażanie przy użyciu capistrano ma ten sam problem (mają one dowiązanie symboliczne od nazwy bieżącej do bieżącej wersji), więc używam aliasów, aby cd do obszarów produkcji / inscenizacji, a także odpowiednio ustawić RAIL_ENV:

alias cdp='export RAILS_ENV=production; echo RAILS_ENV=$RAILS_ENV ; cd /var/www/www.example.com/current'
alias cds='export RAILS_ENV=staging; echo RAILS_ENV=$RAILS_ENV ; cd /var/www/staging.example.com/current'
iheggie
źródło
0

Zakładam, że ścieżka identyfikuje katalog.

Ścieżka do czegoś polega na tym, jak się tam dostać, a nie na samej rzeczy. Ścieżka do twojego łóżka może przebiegać przez pokój, ale gdy już będziesz w łóżku, jeśli ktoś go podniesie i wyniesie na zewnątrz, nie będzie cię już w swoim pokoju.

psusi
źródło
0

Nie jest to samodzielna odpowiedź, ale mam dodatkowy punkt, w którym margines komentarzy był zbyt mały, aby go pomieścić.

Aby lepiej zrozumieć, że katalog w odpowiednich systemach plików jest czymś więcej niż ścieżką, spróbuj przenieść bieżący katalog roboczy innego procesu: w jednej powłoce uruchom interaktywną sesję Pythona:

$ python
>> import os
>> os.getcwd()
'/home/you/hocus'

Następnie przejdź do innej powłoki i przenieś ten katalog:

$ cd /home/you
$ mv hocus pocus

Powrót do pierwotnego:

$ python
>> import os
>> os.getcwd ()
„/ home / you / hocus”
>> os.getcwd ()
„/ home / you / pocus”
Jewgienij Siergiejew
źródło