Perché cd non è un programma?


129

Mi sono sempre chiesto perché cdnon è un programma, ma non sono mai riuscito a trovare la risposta.

Qualcuno sa perché questo è il caso?



1
Ricordo di aver letto (non riesco a trovare dove) che il cdcomando unix originale era un programma separato. Il guscio lo ha gestito specialmente in quanto non lo ha fatto fork, solo exec. E una volta terminato cd, sarebbe stato eseguito sh. Non so se questa è una storia vera.
Camh,

Quale sarebbe il punto? Se aggiungerà una gestione speciale, potrebbe anche chiamare semplicemente il chdirsyscall. fonti: v1 v5 v7 (prima versione con Bourne shell)
Mikel

2
@camh, è una storia vera. L'ho letto anche in un articolo scritto da Dennis M. Ritchie, "L'evoluzione del sistema di condivisione del tempo Unix", AT&T Bell Laboratories Technical Journal 63 (6), parte 2, ottobre 1984.
jlliagre,

@Mikel: sono d'accordo che sembra inutile, ma stavo solo trasmettendo una storia cdche avevo letto. Avevo chiaramente torto su questo aspetto, ora che @jlliagre ha compilato i dettagli.
Camh,

Risposte:


172

Il cdcomando modifica la "directory di lavoro corrente", giusto?

"directory di lavoro corrente" è una proprietà unica per ogni processo.

Quindi, se cdfosse un programma, funzionerebbe così:

  1. cd foo
  2. il cdprocesso inizia
  3. il cdprocesso cambia la directory per il processo cd
  4. il cdprocesso termina
  5. la tua shell ha ancora lo stesso stato, inclusa la directory di lavoro corrente, che aveva prima di iniziare.

8
I tuoi cinque passi sono corretti ma "se cdfosse un programma funzionerebbe così" dovrebbe essere "quando cdviene utilizzato nella sua implementazione esterna del programma, funziona così".
jlliagre,

1
Non essendo un programmatore di sistemi, né avendo una profonda conoscenza dei dettagli dell'interazione con la shell, mi sarei aspettato che la shell esponesse la sua directory di lavoro corrente e che cd fosse un programma che accede e altera quella proprietà. Comprendere, dopo aver visto questa risposta, che probabilmente non è ottimale per come funziona effettivamente per molte ragioni.
Jason,

108

cdoltre ad essere un built-in di shell, in realtà è anche un programma su sistemi operativi POSIX compatibili. Essi devono fornire eseguibili indipendenti per le utilities regolari, come cd. Questo è per esempio il caso di Solaris , AIX , HP-UX e OS X .

Ovviamente, un built-in cdè ancora obbligatorio poiché la sua implementazione esterna non cambia la directory della shell corrente. Tuttavia, quest'ultimo può ancora essere utile. Ecco un esempio che mostra come POSIX prevede come utilizzare questo cdcomando:

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

Su un sistema POSIX, questo oneliner segnalerà un messaggio di errore per tutte le directory in cui non sei autorizzato a entrare cd. Nella maggior parte delle distribuzioni Gnu / Linux, non riesce con quel messaggio di errore:

find: `cd': No such file or directory

Ed ecco la risposta alla tua domanda " Perché cd non è un programma? " Di uno dei co-autori originali di Unix. Su una primissima implementazione di Unix, cd(scritto chdirin quel momento) c'era un programma esterno. Ha smesso di funzionare inaspettatamente dopo essere forkstato implementato per la prima volta.

Citando Dennis Ritchie :

Nel mezzo del nostro giubilo, è stato scoperto che il comando chdir (cambia directory corrente) aveva smesso di funzionare. C'era molta lettura di codice e ansiosa introspezione su come l'aggiunta di fork avrebbe potuto interrompere la chiamata chdir. Alla fine spuntò la verità: nel vecchio sistema chdir era un comando ordinario; ha regolato la directory corrente del processo (unico) collegato al terminale. Con il nuovo sistema, il comando chdir ha modificato correttamente la directory corrente del processo creato per eseguirlo, ma questo processo è stato prontamente terminato e non ha avuto alcun effetto sulla sua shell madre! Era necessario rendere chdir un comando speciale, eseguito internamente all'interno della shell. Si scopre che diverse funzioni simili a comandi hanno la stessa proprietà, ad esempio il login.

Fonte: Dennis M. Ritchie, " L'evoluzione del sistema di condivisione del tempo Unix ", AT&T Bell Laboratories Technical Journal 63 (6), parte 2, ottobre 1984, pagg. 1577–93

La pagina del manuale di chdir di Unix versione 1 (marzo 1971) afferma:

Poiché viene creato un nuovo processo per eseguire ciascun comando, chdir sarebbe inefficace se fosse scritto come un normale comando. È quindi riconosciuto ed eseguito dalla Shell.


10
... quindi, a quanto pare, POSIX impone che ci sia un cdeseguibile indipendente , ma che non deve fare nulla (tranne eventualmente emettere messaggi di errore se chiamato con argomenti sbagliati). Strano.
Ilmari Karonen,

4
Vabbè, se è vero, non sarebbe la cosa più stupida in POSIX.
Kaz,

5
La pagina cd POSIX dice anche "Poiché il cd influenza l'ambiente di esecuzione della shell corrente, viene sempre fornito come un normale shell incorporato".
Mikel,

6
@Kaz, non sono cose completamente diverse. Fanno la stessa cosa, ma solo quello incorporato influenza la shell corrente.
jlliagre,

13
@Kaz: Per favore, non chiamarmi sciocco mentre sto solo segnalando un fatto. Potresti essere d'accordo o in disaccordo con POSIX ma non sparare al messaggero.
jlliagre,

47

Dall'introduzione di Bash ( Cos'è una shell? ):

Le shell forniscono anche un piccolo set di comandi integrati (incorporati) che implementano funzionalità impossibili o scomode da ottenere tramite utility separate. Ad esempio, cd, break, continue, e exec) non può essere attuato all'esterno del guscio perché manipolare direttamente il serbatoio stesso. La history, getopts, kill, o pwdbuiltins, tra gli altri, può essere attuata con utility separate, ma sono più conveniente usare comandi come incorporati. Tutti i builtin della shell sono descritti nelle sezioni successive.


29

Per il pesce d'aprile di quest'anno, ho scritto una versione autonoma dicd .

Nessuno ha preso la battuta. Sospiro.

Chiunque non sia sicuro che cddebba essere integrato nella shell dovrebbe scaricarlo, costruirlo e provarlo.

Leggi anche la sua pagina man. :)


Codice davvero utile! :-)
dschulz,

6
È bello vedere qualcuno che lavora per rendere Gnu / Linux più conforme POSIX. L'implementazione non è solo una buona battuta, ma in realtà manca qualcosa delle distribuzioni Linux ...
jlliagre,

8
Penso che ci riproverò l'anno prossimo, citando il problema POSIX. ;)
Warren Young,

6 anni dopo: bene?
Peter A. Schneider,

@ PeterA.Schneider: ho pensato che fosse chiaro che stavo scherzando, quindi per essere chiari, no, non ho intenzione di spendere un sacco di sforzi nel tentativo di ottenere questo in sistemi operativi OS e simili come Cygwin che attualmente mancanza /bin/cd. Se vuoi prendere il mio codice e renderlo la tua ricerca personale, sei il benvenuto.
Warren Young,

4

Il cdcomando nella shell non può essere un processo separato perché in Unix non esiste alcun meccanismo per modificare la directory di lavoro corrente di un processo diverso (nemmeno il processo padre).

Se cdfosse un processo diverso, dovrebbe cambiare l'attuale directory di lavoro del suo genitore (shell) che non è possibile in Unix. Invece cdè uno speciale comando integrato. La shell chiama funzioni simili chdir()e fchdir() modifica la propria directory di lavoro corrente.

Nota: il kernel memorizza il numero di inode della directory di lavoro corrente per ogni processo. Il processo figlio eredita cwdproviene dal suo genitore.


0

cd è un comando integrato della shell. Facile come è. L'uomo cd dice tutto. il comando cd cambia la directory di lavoro per tutti gli interpreti e (in un ambiente con thread) tutti i thread.


Perché la shell è l'ambiente che si prende cura delle directory di lavoro correnti ($ PDW ...) o cdable_vars. Questo builtin è in definitiva il modo in cui tutti i comandi visibili all'utente dovrebbero cambiare la directory di lavoro corrente. Sei in grado di testarlo in questo modo: compila il bash senza cd.c e prova a scrivere il tuo script cd, che cerca di occuparsi di tutto l'ambiente cdable_vars. Questa domanda è anche più legata allo sviluppatore. Scommetto che potrebbero rispondere a questa domanda in modo più dettagliato.

2
C'è una molto buona ragione tecnica che cdè built-in. Ti suggerirei di leggere le risposte con il punteggio più alto e di considerare come migliorare la tua risposta.
Thorbjørn Ravn Andersen,

La risposta più alta è stata la peggiore che abbia mai letto! Ma eh? Chi sono!

3
Ma risponde alla domanda perché .
Thorbjørn Ravn Andersen,

-1

Penso che una cosa mancante nella risposta delle persone sia che la directory corrente è una variabile d'ambiente che ogni programma può cambiare. Se usi il comando 'export' per vedere la tua attuale lista di variabili d'ambiente, avrai:

declare -x PWD="/home/erfan"

nei tuoi risultati. Quindi con il comando 'cd' vogliamo solo modificare questa variabile interna. Penso che se ci proviamo, possiamo ovviamente inseguire la variabile PWD di qualsiasi pty in shell. Piace:

cder    #change current PTY $PWD variable

Ma penso che non sia necessario in casi normali. In altre parole, prendiamo aiuto da bash (o da qualsiasi shell) per modificare la sua variabile interna definita.


3
Mentre è vero che le shell Bourne espongono l'attuale directory di lavoro (CWD) come $ PWD, questa non è la posizione di archiviazione principale; la posizione effettiva è nella struttura per processo del kernel. È pertanto errato affermare che il CWD "è una variabile di ambiente". Se funzionasse nel modo che suggerisci, questo due righe C stamperebbe il ..percorso, non il percorso da cui lo hai avviato: #include <stdlib.h> int main(void) { chdir(".."); puts(getenv("PWD")); }(comunque, le shell C espongono il CWD come% cwd).
Warren Young,

consente di aggiungere altre righe alla tua app. #include <stdlib.h> int main (void) {chdir (".."); puts (getenv ( "PWD")); setenv (P "PWD", "/", 1); puts (getenv ( "PWD")); } Che cosa avremo come risultati?
Erfankam,

3
Ciò sovrascriverà semplicemente il valore di una variabile, senza effetti collaterali sul CWD. Questo è un test migliore per dimostrare che: #include <unistd.h> int main(void) { char ac[99]; setenv("PWD", "/", 1); puts(getcwd(ac, sizeof(ac))); }mostrerà la directory da cui hai avviato il programma, non /.
Warren Young,

Penso che ogni processo abbia anche una directory di lavoro e una variabile di percorso. Quindi tu chdir cambi semplicemente questo attributo del processo. Shell ha anche questo attributo e con cd modifichiamo questa attribuzione.
Erfankam,

4
No, ti sto dicendo che $PWDha significato solo per la shell Bourne. È solo un modo per la shell di comunicare qualcosa che conosce agli script di shell in modo che non debbano chiamare pwdper trovarlo. Qualsiasi programma autonomo a seconda del valore di $PWDsarà inaffidabile.
Warren Young,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.