Perché il comando `quale` non funziona per` cd`? Non riesco a trovare nemmeno l'eseguibile per `cd`!


30

Ho provato which cde non ha dato un percorso ma invece ha restituito il codice di uscita 1 (verificato con echo $?). Il coreutil cdstesso funziona, quindi l'eseguibile dovrebbe essere lì, giusto? Ho anche eseguito un findfor cd, ma non è stato mostrato alcun file eseguibile. Come viene implementato allora?

Aggiornare:

Non so se dovrei chiedere questo in un altro post ma poiché penso che sia buono qui, sto espandendo (?) Il post ... Quindi la risposta era in realtà abbastanza semplice, non c'è eseguibile per quello - perché è un builtin - Ma ho trovato alcuni builtin (bash shell in Fedora) con i file eseguibili! Quindi builtin -> nessun eseguibile non è giusto suppongo? Forse una risposta che spiega cosa sono effettivamente i builtin (comandi incorporati?), Che in realtà è la questione qui, piuttosto che concentrarsi maggiormente su cd... Alcuni buoni link pubblicati in precedenza indicano che i builtin non sono programmi ... quindi quali sono? Come funzionano? Sono solo funzioni o thread della shell?


1
Leggi questa risposta Si suggerisce di usare il typecomando
c0rp

7
Vedi queste domande e risposte sul perché cddeve essere integrato: perché cd non è un programma? e questo su perché typeè meglio di which: perché non usare "quale"? Cosa usare allora?
terdon,

Domanda simile qui: askubuntu.com/q/613470/178596
Wilf,

Risposte:


46

Il comando cdnon può essere un eseguibile

In una shell, cdviene utilizzato per "andare in un'altra directory", o più formalmente, per modificare la directory di lavoro corrente (CWD). È impossibile implementarlo come comando esterno:

La directory appartiene a un processo

La directory di lavoro corrente è la directory utilizzata per interpretare i percorsi relativi per ottenere un percorso completo che può essere utilizzato per accedere ai file. I percorsi relativi sono utilizzati in molti luoghi e l'interpretazione in un processo non dovrebbe influenzare un altro processo.
Per questo motivo, ogni processo ha la sua directory di lavoro corrente.

cdriguarda la modifica della directory di lavoro corrente del processo di shell, ad esempio bash.

Se fosse un comando esterno, un eseguibile nel percorso, l'esecuzione di tale eseguibile creerebbe un processo con la propria directory di lavoro, senza influenzare quello della shell corrente. Anche se il comando esterno cambierebbe la sua directory, tale modifica scompare quando si chiude il processo esterno.

Comandi incorporati nella shell

Quindi non ha senso eseguire un comando esterno per l'attività di cd. Il comando cddeve applicare una modifica al processo di shell attualmente in esecuzione.

Per fare ciò, è un "comando incorporato" della shell.

I comandi integrati sono comandi che si comportano in modo simile ai comandi esterni, ma sono implementati nella shell (quindi cd non fa parte dei coreutils). Ciò consente al comando di modificare lo stato della shell stessa, in questo caso chiamare call chdir()(vedi man 2 chdir);

Di which

Ora, la risposta alla domanda sul titolo è semplice:
il comando eseguibile whichnon può dirci che cd è un comando incorporato perché un comando eseguibile non sa nulla dei builtin.

Alternativa type -a

In alternativa which, puoi usare type -a; Può vedere comandi eseguibili e builtin; Inoltre, vede alias e funzioni - implementati anche nella shell:

$ type -a cd
cd is a shell builtin
$ type -a type
type is a shell builtin
$ type -a which
which is /usr/bin/which
which is /bin/which

1
Grande spiegazione!
SaltyNuts,

3
Molto meglio della risposta attualmente accettata, questo spiega perché cd è integrata una shell.
Lily Chung,

28

cdè un mandato POSIX shell integrata in :

Se un comando semplice genera un nome comando e un elenco opzionale di argomenti, devono essere eseguite le seguenti azioni:

  1. Se il nome del comando non contiene barre, si verifica il primo passaggio corretto nella sequenza seguente:
    ...
    • Se il nome del comando corrisponde al nome di un'utilità elencata nella tabella seguente, tale utilità deve essere invocata.
      ...
      cd
      ...
    • Altrimenti, il comando deve essere cercato usando il PERCORSO ...

Anche se questo non dice esplicitamente che deve essere un built-in, la specifica prosegue dicendo nella descrizione dicd :

Poiché cd influisce sull'ambiente di esecuzione della shell corrente, viene sempre fornito come un normale built-in della shell.

Dal bashmanuale :

I seguenti comandi incorporati della shell sono ereditati dalla Bourne Shell. Questi comandi sono implementati come specificato dallo standard POSIX.
...

cd
       cd [-L|[-P [-e]]] [directory]

Suppongo che potresti pensare a un'architettura in cui cd non debba essere incorporato. Tuttavia, devi vedere cosa implica un built-in. Se scrivi un codice speciale nella shell per fare qualcosa per un certo comando, ti stai avvicinando ad avere un builtin. Più fai, meglio è semplicemente avere un builtin.

Ad esempio, potresti avere la shell con IPC per comunicare con i sottoprocessi e ci sarebbe un cdprogramma che verificherebbe l'esistenza della directory e se hai i permessi di accesso e quindi comunica con la shell per dirgli di cambiarne directory. Tuttavia, dovrai quindi verificare se il processo di comunicazione con te è un bambino (o creare mezzi speciali di comunicazione solo con i bambini, come un descrittore di file speciale, memoria condivisa, ecc.) E se il processo è in realtà eseguendo il fidatocd programma o qualcos'altro. È un'intera lattina di vermi.

Oppure potresti avere un cdprogramma che fa chdirchiamare il sistema, e avvia una nuova shell con tutte le variabili d'ambiente correnti applicate alla nuova shell, e poi uccide la sua shell madre (in qualche modo) quando fatto. 1

Peggio ancora, potresti persino avere un sistema in cui un processo può alterare gli ambienti di altri processi (penso che tecnicamente puoi farlo con i debugger). Tuttavia un tale sistema sarebbe molto, molto vulnerabile.

Ti ritroverai ad aggiungere sempre più codice per proteggere tali metodi, ed è notevolmente più semplice semplicemente renderlo integrato.


Che qualcosa sia un eseguibile non impedisce che sia incorporato. Caso in questione:

echo e test

echoe testsono utility con mandato POSIX ( /bin/echoe /bin/test). Eppure quasi ogni shell popolare ha un builtin echoe test. Allo stesso modo, killè anche incorporato che è disponibile come programma. Altri includono:

  • sleep (non così comune)
  • time
  • false
  • true
  • printf

Tuttavia, ci sono alcuni casi in cui un comando non può essere altro che un builtin. Uno di questi è cd. In genere, se non viene specificato il percorso completo e il nome del comando corrisponde a quello di un built-in, viene chiamata una funzione adatta a quel comando. A seconda della shell, il comportamento dell'integrato e quello dell'eseguibile possono differire (questo è particolarmente un problema perecho , che ha comportamenti molto diversi . Se vuoi essere certo del comportamento, è preferibile chiamare l'eseguibile usando il percorso completo e impostare variabili come POSIXLY_CORRECT(anche in questo caso non esiste una vera garanzia).

Tecnicamente non c'è nulla che ti impedisca di fornire un sistema operativo che è anche una shell e ha tutti i comandi come integrati. Vicino a questa estremità estrema c'è il monolitico BusyBox . BusyBox è un singolo binario, che (a seconda del nome con cui viene chiamato) può comportarsi come uno degli oltre 240 programmi , incluso Almquist Shell ( ash). Se non si PATHesegue l'impostazione durante l'esecuzione di BusyBox ash, i programmi disponibili in BusyBox sono ancora accessibili all'utente senza specificare a PATH. Si avvicinano all'essere builtin della shell, tranne per il fatto che la shell stessa è una sorta di builtin di BusyBox.


Caso di studio: The Debian Almquist Shell ( dash)

Se guardi l' dashorigine, il thread di esecuzione è qualcosa del genere (ovviamente, con funzioni aggiuntive coinvolte quando vengono utilizzate pipe e altre cose):

maincmdloopevaltreeevalcommand

evalcommandquindi utilizza findcommandper determinare qual è il comando. Se è incorporato, quindi :

 case CMDBUILTIN:
     if (spclbltin > 0 || argc == 0) {
         poplocalvars(1);
         if (execcmd && argc > 1)
             listsetvar(varlist.list, VEXPORT);
     }
     if (evalbltin(cmdentry.u.cmd, argc, argv, flags)) {
         if (exception == EXERROR && spclbltin <= 0) {
             FORCEINTON;
             break;

cmdentry.u.cmdè un struct( struct builtincmd), di cui uno dei componenti è un puntatore a funzione, con una tipica firma di main: (int, char **). La evalbltinfunzione chiama (a seconda che sia incorporato il evalcomando o meno) evalcmdo questo puntatore alla funzione. Le funzioni effettive sono definite in vari file sorgente. echo, ad esempio, è :

int
echocmd(int argc, char **argv)
{
    int nonl;

    nonl = *++argv ? equal(*argv, "-n") : 0;
    argv += nonl;

    do {
        int c;

        if (likely(*argv))
            nonl += print_escape_str("%s", NULL, NULL, *argv++);
        if (nonl > 0)
            break;

        c = *argv ? ' ' : '\n';
        out1c(c);
    } while (*argv);
    return 0;
}

Tutti i collegamenti al codice sorgente in questa sezione sono basati sul numero di riga, quindi possono cambiare senza preavviso.


1 I sistemi POSIX hanno un cdeseguibile .


Nota a margine:

Ci sono molti post eccellenti su Unix e Linux che si occupano del comportamento della shell. In particolare:

Se non hai notato uno schema nelle domande elencate finora, quasi tutte coinvolgono Stéphane Chazelas .


4
Si noti che è possibile ottenere il cdtesto di aiuto con help cd(stessa cosa per tutti i comandi integrati nella shell)
Sylvain Pineau,

@SylvainPineau anche se mi sono collegato al manuale di bash, quel consiglio non è generalmente applicabile ad altre shell, come zsh.
muru,

Effettivamente helpè un build bash (per zsh, è run-help cd)
Sylvain Pineau,

La descrizione collegata dalla specifica POSIX non dice esplicitamente che cddeve essere come shell incorporata ... ma basata sul modo in cui le proprietà del processo e il loro trasferimento funzionano in UNIX cdcome built-in della shell è l'unica implementazione semplice. Vedi la risposta di Volker Siegel .
pabouk,

@pabouk infatti (lo chiama un'utilità), e poi continua dicendo: "Poiché cd influenza l'ambiente di esecuzione della shell corrente, viene sempre fornito come un normale shell incorporato."
muru,

8

Non è possibile trovare un eseguibile cdperché non ce n'è.

cdè un comando interno della tua shell (ad es bash.).


7

da man which:

che restituisce i percorsi dei file (o collegamenti) che verrebbero eseguiti nell'ambiente attuale, se i suoi argomenti fossero dati come comandi in una shell strettamente conforme a POSIX. Lo fa cercando nel PERCORSO i file eseguibili che corrispondono ai nomi degli argomenti. Non segue collegamenti simbolici.

Come possiamo vedere dalla descrizione di which, sta solo verificando PATH. Quindi, se ne hai implementato un po ' bash function, non ti mostrerà nulla. È meglio usare il typecomando insieme a which.

Ad esempio nel lscomando Ubuntu aliasato a ls --color=auto.

$ type ls
ls is aliased to `ls --color=auto'

$ which ls
/bin/ls

E se si implementa la funzione di test hello:

$ function hello() { for i in {1,2,3}; do echo Hello $i;done }
$ which hello

whichnon mostra nulla. Ma type:

$ type hello
hello is a function
hello () 
{ 
    for i in {1,2,3};
    do
        echo Hello $i;
    done
}

Nel tuo caso:

$ type cd
cd is a shell builtin

Ciò significa che cdè una shell integrata , è dentro bash. Tutti i builtin bash descritti in man bash, nella sezione COMANDI INCORPORATI SHELL

SHELL BUILTIN COMMANDS
       Unless otherwise noted, each builtin command documented in this section
       as accepting options preceded by - accepts -- to signify the end of the
       options.   The  :, true, false, and test builtins do not accept options
       and do not treat -- specially.  The exit, logout, break, continue, let,
       and  shift builtins accept and process arguments beginning with - with‐
       out requiring --.  Other builtins that accept  arguments  but  are  not
       specified  as accepting options interpret arguments beginning with - as
       invalid options and require -- to prevent this interpretation.


1
Dovrebbe forse essere enfatizzato di più: non usare which, usare type.
Tripleee
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.