Perché "ls" richiede un processo separato per l'esecuzione?


14

Perché lsrichiede un processo separato per la sua esecuzione? Conosco il motivo per cui comandi come cdnon possono essere eseguiti dal meccanismo di fork, ma c'è del male se lsviene eseguito senza fork?


1
Anche se lsè un programma esterno echo *o echo * .*(a seconda delle opzioni della shell) fa un buon lavoro di elencare i file senza biforcarsi.
Gerrit,

È ancora meglio: printf "% s \ n" *
Costa

Nota sulla diversità delle shell: tcsh ha un builtin ls-Fche agisce come ls -F. È lì per efficienza. Ottieni sempre -Fquale di solito è una buona idea. Se specifichi altre opzioni, punta al comando esterno.

Risposte:


18

La risposta è più o meno lsun eseguibile esterno. Puoi vedere la sua posizione eseguendo type -p ls.

Perché non è lsintegrato nella shell, quindi? Bene, perché dovrebbe essere? Il compito di una shell non è comprendere tutti i comandi disponibili, ma fornire un ambiente in grado di eseguirli. Alcune shell moderne hanno echo, printfe il loro simile come builtin, che tecnicamente non devono essere builtin, ma sono fatti per motivi di prestazioni quando vengono eseguiti ripetutamente (principalmente in loop stretti). Senza renderli predefiniti, la shell dovrebbe eseguire il fork ed eseguire un nuovo processo per ogni chiamata, che potrebbe essere estremamente lento.

Per lo meno, l'esecuzione ls, un eseguibile esterno, richiede l'esecuzione di una delle chiamate di sistema della famiglia exec. Si potrebbe fare questo senza forking, ma sarebbe sostituire la shell primario che si sta utilizzando. Puoi vedere cosa succede in quell'istanza procedendo come segue:

exec ls; echo "this never gets printed"

Poiché l'immagine di processo della shell viene sostituita, la shell corrente non è più accessibile dopo aver fatto ciò. Affinché la shell possa continuare a funzionare dopo aver eseguito ls, il comando dovrebbe essere integrato nella shell.

Forking consente la sostituzione di un processo che non è la shell principale, il che significa che è possibile continuare a eseguire la shell in seguito.


1
Penso che si stia chiedendo perché ls (1) non sia una funzionalità integrata di shell, che qualcuno dovrebbe spiegare come diversi fornitori hanno opzioni diverse per ls (1) e sono in grado di interrogare cose diverse dal filesystem, ecc. E anche gli alti e bassi soprattutto di averlo "incorporato" nella shell.
llua,

@llua ho aggiunto alcune informazioni su questo, e nei casi di eccezione di echo, printfe così via
Chris giù

Non è sempre chiaro perché alcune cose siano integrate e altre no. Ad esempio, perché cdnon è un eseguibile esterno?
Faheem Mitha,

@FaheemMitha V'è un esterna cdeseguibile in sistemi operativi POSIX-compliant ( vedi qui ). Se vuoi effettivamente chdir () nel processo corrente, però, devi averlo incorporato nella shell.
Chris Down,

è diventato un'abitudine perché lsè esterno, ma può anche essere implementato in una shell. Vedi busybox.

15

Il Manuale di riferimento di Bash afferma:

I comandi integrati sono necessari per implementare funzionalità impossibili o scomode da ottenere con utility separate.

Cioè, le shell sono progettate per includere comandi integrati solo se:

  1. Richiesto dallo standard POSIX
  2. Comandi che richiedono l'accesso alla shell stessa, come gli incorporati di controllo del lavoro
  3. Comandi che sono molto semplici, non dipendenti dal sistema operativo e aumentano l'efficienza di esecuzione quando implementati come incorporati, come printf

Il lscomando non soddisfa nessuno dei requisiti di cui sopra.

Tuttavia , qui non ci sono vincoli di programmazione che potrebbero impedire lsl'implementazione come built-in, che si sta eseguendo nello stesso processo dell'interprete bash. Le ragioni di progettazione per i comandi che non vengono impiantati come built-in della shell sono:

  1. La shell dovrebbe essere separata dal filesystem - nessun comando integrato dovrebbe dipendere dal corretto funzionamento di qualsiasi filesystem o dispositivo periferico
  2. Un comando che potrebbe essere di tipo filesystem o dipendente dal sistema operativo dovrebbe essere un eseguibile separato
  3. Un comando che potresti voler convogliare verso o da cui dovrebbe essere un processo separato
  4. Un comando che potresti voler eseguire in background dovrebbe essere un eseguibile separato
  5. Un comando che ha un gran numero di possibili parametri è meglio implementato in un eseguibile separato
  6. I comandi che dovrebbero avere lo stesso output, indipendentemente dal tipo di shell (bash, csh, tsh, ...) che li invoca dovrebbero essere eseguibili autonomi

Per quanto riguarda il primo motivo: vuoi che la shell sia il più indipendente e resiliante possibile. Non vuoi che la shell rimanga bloccata su lsun mount NFS che "non risponde ancora provando".

Per quanto riguarda il secondo motivo: in molti casi potresti voler utilizzare una shell per un sistema che utilizza Busybox o un altro file system con lsun'implementazione diversa . O persino utilizzare la stessa sorgente di shell nei sistemi operativi che hanno lsimplementazioni diverse .

Per quanto riguarda la terza ragione: per espressioni come find . -type d | xargs ls -ladquesta sarebbe difficile o impossibile implementare lslo stesso processo dell'interprete della shell.

Per quanto riguarda il quarto motivo: alcuni lscomandi possono richiedere molto tempo per il completamento. Nel frattempo potresti volere che la shell continui a fare qualcos'altro.


Nota: vedi questo utile post di Warren Young in risposta a una domanda simile.


Hai perso la facilità di eseguire il piping dell'output se è un comando separato e tutta la programmazione che ci vorrebbe per reindirizzare una primitiva di shell in un eseguibile separato.
Bruce Ediger,

@BruceEdiger: che piacere ricevere un commento dallo stimato BE. Grazie! Credo che la ragione 3 copra il tuo commento, no?
Jonathan Ben-Avraham,

1
Stavo pensando più in linea a quanto sarebbe complicato il codice sorgente della shell stessa se dovesse gestire pipe per processi esterni e inoltrare l'output di un comando interno come l'ipotetico lsin un processo esterno. Potrebbe essere fatto, ma sarebbe complicato.
Bruce Ediger,

1
Temo di più se non tutti i tuoi 5 punti sono discutibili. 1: ls è (si spera) indipendente dall'implementazione del file system. Spetta al kernel fornire un'interfaccia coerente alla libreria e alle applicazioni standard. 2: ls è probabilmente meno dipendente dal sistema operativo rispetto alla shell. 3: shells consente sicuramente incorporati nelle pipeline. 4: le shell consentono sicuramente l'esecuzione dei builtin in background. 5: è abbastanza soggettivo.
jlliagre,

1
@ JonathanBen-Avraham @BruceEdiger Le conchiglie non gestiscono già il case del pipe per i builtin con subshells? ad es . bashuscita alias | grep ls. inputcat /etc/passwd | while read a; do echo "$a"; done
Matt

2

lsnon richiede un processo separato. Pochissimi comandi in realtà richiedono un processo separato: solo quelli che devono cambiare i privilegi.

Di norma, le shell implementano i comandi come builtin solo quando tali comandi devono essere implementati come builtin. Comandi come alias, cd, exit,export , jobs, ... necessità di leggere o modificare alcune stato interno del guscio, e pertanto non può essere programmi separati. I comandi che non hanno tali requisiti possono essere comandi separati; in questo modo, possono essere chiamati da qualsiasi shell o altro programma.

Guardando l'elenco dei builtin in bash, solo i seguenti builtin possono essere implementati come comandi separati. Per alcuni, ci sarebbe una leggera perdita di funzionalità.

  • command - ma perderebbe la sua utilità in situazioni in cui PATH potrebbe non essere impostato correttamente e lo script sta usando commandcome parte della sua configurazione.
  • echo - è integrato per l'efficienza.
  • help - potrebbe utilizzare un database separato, ma l'incorporamento del testo di aiuto nell'eseguibile della shell ha il vantaggio di rendere autonomo l'eseguibile della shell.
  • kill - ci sono due vantaggi nell'avere un builtin: può riconoscere le designazioni di lavoro oltre agli ID di processo e può essere utilizzato anche quando non ci sono risorse sufficienti per avviare un processo separato.
  • printf- per lo stesso motivo di echo, e anche per supportare l' -vopzione di mettere l'output in una variabile.
  • pwd - il built-in offre la capacità aggiuntiva di tracciare la directory corrente logica (lasciando intatti i collegamenti simbolici invece di espanderli).
  • test - è integrato per l'efficienza (e bash fa anche un po 'di magia con i file chiamati /dev/fd/… su alcuni sistemi operativi).

Alcune shell offrono un numero significativo di builtin aggiuntivi. C'è sash , che è una shell progettata per essere un binario autonomo per le riparazioni di emergenza (quando alcuni comandi esterni potrebbero non essere utilizzabili). Ha un built-in ls, chiamato -ls, così come altri strumenti come -grepe -tar. I built-in di Sash hanno meno capacità rispetto ai comandi completi. Zsh offre alcuni builtin simili nel suo modulo zsh / files . Non ha ls, ma espansione jolly ( echo *) e zstatpuò svolgere una funzione simile.


2

Penso che qualcosa che manca alla gente qui sia la complessità di taglio del lsprogramma GNU su Linux. Confrontando la dimensione eseguibile di lscon bashe dashshell sul mio sistema Debian, vediamo che è abbastanza grande:

graeme@graeme:~$ ls -lh /bin/{ls,bash,dash}
-rwxr-xr-x 1 root root 953K Mar 30  2013 /bin/bash
-rwxr-xr-x 1 root root 115K Dec 25 20:25 /bin/dash
-rwxr-xr-x 1 root root 108K Jul 20 22:52 /bin/ls

Includere una funzionalità lscompleta come la versione GNU bashaumenterebbe la dimensione dell'eseguibile del 10%. Ha quasi le stesse dimensioni dell'intero dashguscio!

La maggior parte dei builtin della shell sono scelti perché si integrano con la shell in un modo che gli eseguibili esterni non possono (la domanda sottolinea cd, ma un altro esempio è la versione bash killdell'integrazione con il controllo del lavoro bash) o perché sono comandi molto semplici da implementare, dando un grande guadagno rispetto alla dimensione (true e falsesono quasi semplici come si arriva).

GNU lsha avuto un lungo ciclo di sviluppo e implementa le opzioni possibili per personalizzare quali / come visualizzare i risultati. L'uso di un predefinito per impostazione predefinita perderebbe questa funzionalità o aumenterebbe significativamente la complessità e le dimensioni della shell.


1

cdè integrato nella shell, lsè un programma separato che vedrai su /bin/ls.


0

Questo fa quello che stai cercando:

printf "%s\n" *

Inoltre puoi archiviare i nomi dei file in array:

files=(`printf "%s\n" *`)  #items are separated by whitespace
echo ${#files[*]} files
for index in ${!a[*]}
do printf "%d: %s\n" $index ${a[$index]};
done

Ma non importa degli spazi nei nomi.
Passa alla variabile e si preoccupa degli spazi:

printf "%s\n" * | while read a; do echo $a; done
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.