Cosa fa un comando "exec"?


107

Non capisco il comando bash exec. L'ho visto usato negli script per reindirizzare tutto l'output su un file (come visto in questo ). Ma non capisco come funziona o cosa fa in generale. Ho letto le pagine man ma non le capisco.


Conoscete chi è un processo ?
fkraiem,

1
@fkraiem che vuoi dire?
becko,

Scusa, volevo dire "cosa". : p Ma la risposta sembra essere no.
fkraiem,

Ma in realtà il tuo script usa execin un modo speciale che può essere spiegato molto più semplicemente, scriverò una risposta.
fkraiem,

Risposte:


88

man bash dice:

exec [-cl] [-a name] [command [arguments]]
      If command is specified, it replaces the shell.  No new  process
      is  created.  The arguments become the arguments to command.  If
      the -l option is supplied,  the  shell  places  a  dash  at  the
      beginning  of  the  zeroth  argument passed to command.  This is
      what login(1) does.  The -c option causes command to be executed
      with  an empty environment.  If -a is supplied, the shell passes
      name as the zeroth argument to the executed command.  If command
      cannot  be  executed  for  some  reason, a non-interactive shell
      exits, unless the execfail shell option  is  enabled.   In  that
      case,  it returns failure.  An interactive shell returns failure
      if the file cannot be executed.  If command  is  not  specified,
      any  redirections  take  effect  in  the  current shell, and the
      return status is 0.  If there is a redirection error, the return
      status is 1.

Le ultime due righe sono importanti: se si esegue execda solo, senza un comando, i reindirizzamenti verranno semplicemente applicati alla shell corrente. Probabilmente sai che quando esegui command > file, l'output di commandviene scritto fileinvece che sul tuo terminale (questo si chiama reindirizzamento ). Se exec > fileinvece esegui , il reindirizzamento si applica all'intera shell: qualsiasi output prodotto dalla shell viene scritto fileinvece che sul tuo terminale. Per esempio qui

bash-3.2$ bash
bash-3.2$ exec > file
bash-3.2$ date
bash-3.2$ exit
bash-3.2$ cat file
Thu 18 Sep 2014 23:56:25 CEST

In primo luogo inizio una nuova bashshell. Quindi, in questa nuova shell exec > file, corro , in modo che tutto l'output venga reindirizzato a file. In effetti, dopo che corro datema non ottengo alcun output, perché l'output viene reindirizzato a file. Quindi esco dalla shell (in modo che il reindirizzamento non si applichi più) e vedo che fileeffettivamente contiene l'output del datecomando eseguito in precedenza.


42
Questa è solo una spiegazione parziale. execserve anche a sostituire l'attuale processo di shell con un comando, in modo tale che genitore faccia un modo e figlio possieda pid. Questo non è solo per il reindirizzamento. Per favore aggiungi queste informazioni
Sergiy Kolodyazhnyy

3
In seguito al commento di @ SergiyKolodyazhnyy, l'esempio che ho appena incontrato che mi ha portato a questa pagina è un docker-entrypoint.sh, dove dopo aver eseguito varie azioni sulla configurazione di nginx, l'ultima riga dello script è exec nginx <various nginx arguments>. Ciò significa che nginx prende il controllo del pid dello script bash e ora nginx è il principale processo in esecuzione del contenitore, non lo script. Presumo che questo sia solo per la pulizia, a meno che qualcun altro non conosca una ragione più concreta per questo?
Luke Griffiths,

1
@Luke Questo si chiama "script wrapper". Ne è anche un esempio gnome-terminal, che almeno il 14.04 aveva uno script wrapper per impostare argomenti. E questo è il loro unico scopo, davvero - impostare arti e ambiente. Un altro caso sarebbe quello di ripulire - uccidere prima l'istanza precedente di un processo e lanciarne uno nuovo
Sergiy Kolodyazhnyy

un altro execesempio simile nginxall'esempio fornito da @LukeGriffiths è lo ~/.vnc/xstartupscript che vncserverutilizza per configurare un processo del server VNC e quindi exec gnome-sessiono exec startkdecosì via.
Trevor Boyd Smith, il

@LukeGriffiths, il motivo principale di execuno script di avvio del contenitore è che il PID 1, ENTRYPOINT del contenitore, ha un significato speciale in Docker. È un processo principale che riceve segnali e, quando esiste, esce anche il contenitore. execsolo un modo per shuscire da questa catena di comando e rendere il demone il processo principale del contenitore.
kkm

45

exec è un comando con due comportamenti molto distinti, a seconda che venga usato almeno un argomento o che non venga usato alcun argomento.

  • Se viene passato almeno un argomento, il primo viene preso come nome di comando e exectenta di eseguirlo come comando passando gli eventuali argomenti rimanenti a quel comando e gestendo gli eventuali reindirizzamenti.

  • Se il comando passato come primo argomento non esiste, la shell corrente, non solo il comando exec, esce per errore.

  • Se il comando esiste ed è eseguibile, sostituisce la shell corrente. Ciò significa che se execappare in uno script, le istruzioni che seguono la chiamata exec non verranno mai eseguite (a meno che non execsi trovi in ​​una subshell). execnon ritorna mai. Neanche le trappole della shell come "EXIT" verranno attivate.

  • Se non viene passato alcun argomento, execviene utilizzato solo per ridefinire i descrittori del file shell corrente. La shell continua dopo exec, a differenza del caso precedente, ma lo standard input, output, errore o qualunque altro descrittore di file sia stato reindirizzato ha effetto.

  • Se alcuni reindirizzamenti utilizzano /dev/null, qualsiasi input da esso restituirà EOF e qualsiasi output ad esso verrà scartato.

  • È possibile chiudere i descrittori di file utilizzando -come origine o destinazione, ad es exec <&-. Le successive letture o scritture falliranno.

Ecco due esempi:

echo foo > /tmp/bar
exec < /tmp/bar # exec has no arguments, will only affect current shell descriptors, here stdin
cat # simple command that read stdin and write it to stdout

Questo script genererà "pippo" come comando cat, invece di attendere l'input dell'utente come avrebbe fatto nel solito caso prenderà il suo input dal file / tmp / bar che contiene pippo.

echo foo > /tmp/bar
exec wc -c < /tmp/bar # exec has two arguments, the control flow will switch to the wc command
cat

Questo script visualizzerà 4(il numero di byte in / tmp / bar) e termina immediatamente. Il catcomando non verrà eseguito.


4
`Alcuni vecchi post non invecchiano mai ... +1.
Cbhihe,

3
Se alcuni reindirizzamenti utilizzano / dev / null, il descrittore di file associato viene chiuso. No, reindirizza davvero a / da /dev/null, quindi le scritture hanno ancora successo e le letture restituiscono EOF. close(2)su un fd farebbe sì che le chiamate di sistema in lettura / scrittura restituissero errori, e lo fai con exec 2>&-per esempio.
Peter Cordes,

2
Provalo tu stesso: exec 3</dev/null; ls -l /proc/self/fdnota che fd 3 sarà aperto in sola lettura su / dev / null. Quindi chiudilo di nuovo con exec 3<&-, e puoi vedere (con di ls -l /proc/$$/fdnuovo) che il tuo processo di shell non ha più fd 3. (la chiusura di stdin con exec <&-può essere utile negli script, ma interattivamente è un logout.)
Peter Cordes

@PeterCordes Hai assolutamente ragione. Risposta aggiornata Grazie!
jlliagre,

1
Questa risposta è ottima perché spiega i due casi d'uso execdell'attuale risposta più votata parla solo del caso d'uso e l'altra risposta di g_p parla solo dell'altro caso d'uso. E questa risposta è piacevole e concisa / leggibile per un argomento così complesso.
Trevor Boyd Smith, il

33

Per capire execdevi prima capire fork. Sto cercando di farla breve.

  • Quando arrivi a un bivio, generalmente hai due opzioni. I programmi Linux raggiungono questo bivio quando colpiscono una fork()chiamata di sistema.

  • I programmi normali sono comandi di sistema che esistono in una forma compilata sul tuo sistema. Quando viene eseguito un tale programma, viene creato un nuovo processo. Questo processo figlio ha lo stesso ambiente del suo genitore, solo il numero ID del processo è diverso. Questa procedura si chiama biforcazione .

  • Il forking fornisce un modo per un processo esistente di avviarne uno nuovo. Tuttavia, potrebbero esserci situazioni in cui un processo figlio non fa parte dello stesso programma del processo padre. In questo caso execviene utilizzato. exec sostituirà il contenuto del processo attualmente in esecuzione con le informazioni di un programma binario.
  • Dopo il processo di fork, lo spazio degli indirizzi del processo figlio viene sovrascritto con i nuovi dati di processo. Questo viene fatto tramite una chiamata exec al sistema.

3
puoi spiegare perché execposso reindirizzare un output di script, come nel link che ho pubblicato?
becko,

1
Ho trovato questo poco chiaro "Tuttavia, ci possono essere situazioni in cui un processo figlio non fa parte dello stesso programma del processo padre"
cdosborn,

6

In bash, se lo fai help exec:

$ help exec
exec: exec [-cl] [-a name] [command [arguments ...]] [redirection ...]
    Replace the shell with the given command.

    Execute COMMAND, replacing this shell with the specified program.
    ARGUMENTS become the arguments to COMMAND.  If COMMAND is not specified,
    any redirections take effect in the current shell.

    Options:
      -a name   pass NAME as the zeroth argument to COMMAND
      -c        execute COMMAND with an empty environment
      -l        place a dash in the zeroth argument to COMMAND

    If the command cannot be executed, a non-interactive shell exits, unless
    the shell option `execfail' is set.

    Exit Status:
    Returns success unless COMMAND is not found or a redirection error occurs.

Il bit rilevante:

If COMMAND is not specified, any redirections take effect in the current shell.

execè un built-in di shell , che è l'equivalente di shell della execfamiglia di chiamate di sistema di cui parla G_P (e di cui sembra aver letto le manpage). Ha solo la funzionalità POSIX obbligatoria di influenzare la shell corrente se non viene specificato alcun comando.

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.