Dlaczego cd nie jest programem?


128

Zawsze zastanawiałem się, dlaczego cdnie jest programem, ale nigdy nie udało mi się znaleźć odpowiedzi.

Czy ktoś wie, dlaczego tak jest?



1
Pamiętam, że czytałem (nie mogę znaleźć gdzie), że oryginalna cdkomenda unix była osobnym programem. Powłoka obchodzić go specjalnie w tym, że nie forktylko exec. A kiedy cdto się skończy, wykona polecenie sh. Nie wiem, czy to prawdziwa historia.
camh

Jaki byłby sens? Jeśli ma dodać specjalną obsługę, równie dobrze może po prostu wywołać chdirsyscall. źródła: v1 v5 v7 (pierwsza wersja z powłoką Bourne'a)
Mikel

2
@camh, to prawdziwa historia. Przeczytałem to również w artykule Dennisa M. Ritchiego, „Ewolucja uniksowego systemu dzielenia czasu”, AT&T Bell Laboratories Technical Journal 63 (6), część 2, październik 1984 r.
jlliagre

@Mikel: Zgadzam się, że wydaje się to bezcelowe, ale właśnie opowiadałem o cdtym, co przeczytałem. Wyraźnie się myliłem co do tego aspektu, skoro @jlliagre podało szczegóły.
camh

Odpowiedzi:


171

cdPolecenie modyfikuje „bieżący katalog roboczy”, prawda?

„bieżący katalog roboczy” jest właściwością unikalną dla każdego procesu.

Gdyby więc cdbył to program, działałby tak:

  1. cd foo
  2. cdrozpoczyna się proces
  3. cdproces zmienia katalog dla procesu cd
  4. z cdwyjścia procesowe
  5. twoja powłoka nadal ma ten sam stan, w tym bieżący katalog roboczy, co przed uruchomieniem.

8
Pięć kroków jest poprawnych, ale „jeśli cdbyłby to program, działałby tak, jak powinien”, powinien być „w przypadku cdużycia go w zewnętrznej realizacji programu, działa on w ten sposób”.
jlliagre

1
Nie będąc programistą systemów ani nie mając głębokiej wiedzy na temat tajników interakcji z powłoką, spodziewałbym się, że powłoka ujawni swój bieżący katalog roboczy, a cd będzie programem, który uzyskuje dostęp i zmienia tę właściwość. Zrozumienie, po przeanalizowaniu tej odpowiedzi, że jest to prawdopodobnie nieoptymalne z punktu widzenia faktycznego działania z wielu powodów.
Jason

108

cdoprócz tego, że jest wbudowaną powłoką, w rzeczywistości jest także programem w systemach operacyjnych zgodnych z POSIX. Oni muszą zapewnić niezależne pliki wykonywalne dla zwykłych narzędzi, jak cd. Jest to na przykład miejsce w przypadku systemu Solaris , AIX , HP-UX i OSX .

Oczywiście wbudowane narzędzie cdjest nadal obowiązkowe, ponieważ jego zewnętrzna implementacja nie zmienia bieżącego katalogu powłoki. To ostatnie może być jednak nadal przydatne. Oto przykład pokazujący, jak POSIX wyobraża sobie, jak cdmożna użyć tego polecenia:

find . -type d -exec cd {} \;

W systemie POSIX ten oneliner zgłasza komunikat o błędzie dla wszystkich katalogów, do których nie wolno ci wchodzić cd. W większości dystrybucji Gnu / Linux nie wyświetla się ten komunikat o błędzie:

find: `cd': No such file or directory

Oto odpowiedź na pytanie „ Dlaczego cd nie jest programem? ” Jednego z oryginalnych współautorów Uniksa. Na bardzo wczesnej implementacji Uniksa cd( chdirw tym czasie pisownia ) był programem zewnętrznym. Właśnie przestał działać nieoczekiwanie po forkpierwszym wdrożeniu.

Cytując Dennisa Ritchiego :

W trakcie naszej radości odkryto, że polecenie chdir (zmień katalog bieżący) przestało działać. Było dużo czytania kodu i niepokojąca introspekcja o tym, jak dodanie widelca mogło przerwać połączenie chdir. W końcu dotarła prawda: w starym systemie chdir było zwykłym poleceniem; dostosowało bieżący katalog (unikalnego) procesu dołączonego do terminala. W nowym systemie komenda chdir poprawnie zmieniła bieżący katalog procesu utworzonego w celu jego wykonania, ale proces ten został natychmiast zakończony i nie miał żadnego wpływu na jego powłokę nadrzędną! Konieczne było uczynienie chdir specjalnym poleceniem wykonywanym wewnętrznie w powłoce. Okazuje się, że kilka funkcji podobnych do poleceń ma tę samą właściwość, na przykład logowanie.

Źródło: Dennis M. Ritchie, „ Ewolucja uniksowego systemu podziału czasu ”, AT&T Bell Laboratories Technical Journal 63 (6), część 2, październik 1984, s. 1577–93

Strona podręcznika chdir dla Unix Version 1 (marzec 1971) stwierdza:

Ponieważ tworzony jest nowy proces do wykonania każdej komendy, chdir byłby nieskuteczny, gdyby został napisany jako normalna komenda. Jest zatem rozpoznawany i wykonywany przez Shell.


10
... więc najwyraźniej POSIX nakazuje, aby istniał niezależny cdplik wykonywalny, ale nie powinien nic robić (oprócz ewentualnego emitowania komunikatów o błędach, jeśli zostanie wywołany z niewłaściwymi argumentami). Dziwne.
Ilmari Karonen

4
No cóż, jeśli to prawda, nie byłaby to najgłupsza rzecz w POSIX.
Kaz

5
Strona cd POSIX mówi także: „Ponieważ cd wpływa na bieżące środowisko wykonywania powłoki, zawsze jest dostarczany jako zwykła wbudowana powłoka”.
Mikel

6
@Kaz, nie są to zupełnie różne rzeczy. Robią to samo, ale tylko wbudowany wpływa na bieżącą powłokę.
jlliagre

13
@Kaz: Nie dzwoń do mnie głupio, gdy tylko zgłaszam jakiś fakt. Możesz zgodzić się z POSIX lub nie, ale nie strzelaj do posłańca.
jlliagre

47

Ze wstępu do Bash ( Co to jest powłoka? ):

Powłoki zapewniają również niewielki zestaw wbudowanych poleceń (wbudowanych) implementujących funkcje niemożliwe lub niewygodne do uzyskania za pomocą oddzielnych narzędzi. Na przykład cd, break, continuei exec) nie może być realizowane na zewnątrz powłoki, ponieważ bezpośrednie manipulowanie samej powłoki. history, getopts, kill, Lub pwdbuiltins, między innymi, mogą być realizowane w oddzielnych narzędzi, ale są bardziej wygodne w użyciu jako wbudowanych poleceń. Wszystkie wbudowane powłoki zostały opisane w kolejnych sekcjach.


29

Na April Fool's w tym roku napisałem samodzielną wersjęcd .

Nikt nie żartuje. Westchnienie.

Każdy, kto nie jest pewien, czy cdmusi to być wbudowane w powłokę, powinien ją pobrać, zbudować i wypróbować.

Przeczytaj także jego stronę podręcznika. :)


Naprawdę przydatny kod! :-)
dschulz

6
Dobrze, że widzisz kogoś pracującego nad zwiększeniem zgodności Gnu / Linux z POSIX. Twoja implementacja to nie tylko dobry żart, ale w rzeczywistości czegoś brakuje w dystrybucjach Linuksa ...
jlliagre

8
Myślę, że spróbuję ponownie w przyszłym roku, powołując się na problem POSIX. ;)
Warren Young

6 lat później: dobrze?
Peter A. Schneider,

@ PeterA.Schneider: Myślałem, że to jasne, że żartuję, więc, żeby być jasnym, nie, nie zamierzam poświęcać dużo wysiłku, próbując dostać się do systemów operacyjnych i projektów podobnych do systemu operacyjnego, takich jak Cygwin, które brak /bin/cd. Jeśli chcesz wziąć mój kod i zrobić z niego osobistą misję, możesz to zrobić.
Warren Young,

4

cdPolecenie w powłoce nie może być oddzielny proces w systemie Unix ponieważ nie ma mechanizmu, aby zmienić bieżący katalog roboczy inny proces (nawet proces nadrzędny).

Gdyby cdbył to inny proces, musiałby zmienić bieżący katalog roboczy swojego rodzica (powłoki), co nie jest możliwe w Uniksie. Zamiast tego cdjest specjalne wbudowane polecenie. Wywołania powłoki działają jak chdir()i fchdir() zmieniają własny bieżący katalog roboczy.

Uwaga: jądro przechowuje numer i-węzła bieżącego katalogu roboczego dla każdego procesu. Proces potomny dziedziczy go po cwdrodzicu.


0

cd jest wbudowanym poleceniem powłoki. Tak proste jak jest. Ten człowiek mówi wszystko. polecenie cd zmienia katalog roboczy dla wszystkich interpreterów i (w środowisku wątków) wszystkich wątków.


Ponieważ powłoka jest środowiskiem, które dba o twoje aktualne katalogi ($ PDW ...) lub cdable_vars. To wbudowane jest ostatecznie sposobem, w jaki wszystkie widoczne dla użytkownika polecenia powinny zmienić bieżący katalog roboczy. Możesz to przetestować w ten sposób: skompiluj bash bez cd.c i spróbuj napisać własny skrypt cd, który próbuje zająć się całym środowiskiem cdable_vars. To pytanie jest również bardziej związane z programistą. Założę się, że mogą odpowiedzieć na to pytanie bardziej szczegółowo.

2
Istnieje bardzo dobry powód techniczny, który cdjest wbudowany. Sugeruję przeczytanie odpowiedzi najwyżej ocenionych i zastanowienie się, w jaki sposób można poprawić odpowiedź.
Thorbjørn Ravn Andersen

Najwyżej oceniana odpowiedź była najgorsza, jaką kiedykolwiek czytałem! Ale co? Kim jestem!

3
Ale odpowiada na pytanie dlaczego .
Thorbjørn Ravn Andersen

-1

Myślę, że w ludziach brakuje jednej odpowiedzi: bieżący katalog to zmienna środowiskowa, którą każdy program może zmienić. Jeśli użyjesz polecenia „eksportuj”, aby wyświetlić listę bieżących zmiennych środowiskowych, będziesz mieć:

declare -x PWD="/home/erfan"

w twoich wynikach. Dlatego za pomocą polecenia „cd” chcemy po prostu zmodyfikować tę zmienną wewnętrzną. Myślę, że jeśli spróbujemy, możemy zmienić zmienną PWD dowolnego pty w powłoce, oczywiście. Lubić:

cder    #change current PTY $PWD variable

Ale myślę, że nie ma takiej potrzeby w normalnych przypadkach. Innymi słowy, korzystamy z pomocy bash (lub dowolnej powłoki), aby zmodyfikować zdefiniowaną zmienną wewnętrzną.


3
Chociaż prawdą jest, że powłoki Bourne'a ujawniają bieżący katalog roboczy (CWD) jako $ PWD, nie jest to podstawowa lokalizacja przechowywania; rzeczywista lokalizacja znajduje się w strukturze poszczególnych procesów jądra. Dlatego błędne jest twierdzenie, że CWD „jest zmienną środowiskową”. Jeśli zadziałałoby to tak, jak sugerujesz, ten dwuliniowy C wydrukowałby ..ścieżkę, a nie ścieżkę, od której ją zacząłeś: #include <stdlib.h> int main(void) { chdir(".."); puts(getenv("PWD")); }(Nawiasem mówiąc, powłoki C eksponują CWD jako% cwd.)
Warren Young

pozwala dodać kolejne wiersze do Twojej aplikacji. #include <stdlib.h> int main (void) {chdir (".."); puts (getenv („PWD”)); setenv (P „PWD”, „/”, 1); puts (getenv („PWD”)); } Co będziemy mieli jako wyniki?
Erfankam

3
To po prostu nadpisze wartość zmiennej, bez efektu ubocznego na CWD. Jest to lepszy test pokazujący, że: #include <unistd.h> int main(void) { char ac[99]; setenv("PWD", "/", 1); puts(getcwd(ac, sizeof(ac))); }pokaże katalog, z którego uruchomiłeś program, a nie /.
Warren Young,

Myślę, że każdy proces ma również katalog roboczy i zmienną ścieżkową. Zatem przez chdir po prostu zmieniasz ten atrybut procesu. Shell ma również ten atrybut i za pomocą cd modyfikujemy tę atrybut.
Erfankam

4
Nie, mówię ci, że $PWDma to znaczenie tylko dla powłoki Bourne'a. Jest to po prostu sposób, aby powłoka komunikowała coś, co zna skrypty powłoki, więc nie muszą dzwonić, pwdaby to znaleźć. Każdy samodzielny program w zależności od wartości $PWDbędzie zawodny.
Warren Young,
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.