Caso d'uso / esempio pratico per exec incorporato di Bash


Risposte:


18

execviene spesso utilizzato negli script di shell che fungono principalmente da wrapper per l'avvio di altri binari. Per esempio:

#!/bin/sh

if stuff;
    EXTRA_OPTIONS="-x -y -z"
else
    EXTRA_OPTIONS="-a foo"
fi

exec /usr/local/bin/the.real.binary $EXTRA_OPTIONS "$@"

in modo che al termine dell'esecuzione del wrapper, il binario "reale" prende il sopravvento e non vi è più traccia dello script del wrapper che occupasse temporaneamente lo stesso slot nella tabella dei processi. Il binario "reale" è un figlio diretto di qualunque cosa lo lanciasse invece di un nipote.

Nella tua domanda menzioni anche il reindirizzamento I / O. Questo è un caso d'uso piuttosto diverso exece non ha nulla a che fare con la sostituzione della shell con un altro processo. Quando execnon ha argomenti, in questo modo:

exec 3>>/tmp/logfile

quindi i reindirizzamenti I / O sulla riga di comando diventano effettivi nel processo di shell corrente, ma il processo di shell corrente continua a essere eseguito e passa al comando successivo nello script.


1
Si può dire che i due casi sono correlati in questo per entrambi, execdice alla shell di non fare l'azione (eseguire un comando o eseguire un reindirizzamento) in un processo figlio, ma nello stesso processo.
Stéphane Chazelas,

5

Ho usato un shell execincorporato per ottenere un ID di processo (PID) in un programma Java. Potrebbe esserci un modo per ottenere PID dall'interno di Java ora, ma diversi anni fa non lo era. Una volta che un processo ha il proprio PID, può scriverlo in un file PID (cercare /var/run/i nomi dei file con un suffisso '.pid') per consentire ai programmi di gestione di conoscere il PID del processo in esecuzione e impedire una seconda istanza dello stesso server in esecuzione. Funziona in questo modo:

exec java -cp=YourServer.jar StartClass -p $$

Il codice nel main()metodo di classe StartClassgestisce l'analisi degli argomenti e può trovare il proprio ID di processo.


2

Per divertimento, esegui il seguente programma (tradotto nella lingua di implementazione scelta) in background su un sistema con contabilità e limiti del processo utente.

while(true) fork();

Ora che ogni slot nella tabella dei processi che ti è permesso usare è pieno di copie di quel programma in esecuzione, come intendi ucciderlo? Il lancio di kill (1) richiede un altro slot di processo, che non puoi avere. Sarebbe sicuramente utile far sostituire la shell con il comando kill ...

exec /bin/kill -9 -1

(Suppone che il tuo sistema abbia kill (1) in / bin / kill. "Exec` che kill` -9 -1 "è potenzialmente più sicuro.) Questo invia SIGKILL a ogni processo che puoi.

(Nota: non disconnettersi dalla shell di avvio a meno che i limiti del processo non consentano sempre a un nuovo accesso uno slot di processo per la sua shell. Se lo si fa, può essere un po 'più difficile ripulire. primi anni '90. No.)


3
(1) Questa risposta sarebbe leggermente migliore se effettivamente mostrassi il execcomando che sarebbe utile in questa situazione. (2) Questa risposta è in qualche modo arcaica; il killcomando è stato incorporato in bash per molti anni, in gran parte a causa di questa preoccupazione.
G-Man dice "Ripristina Monica" il

@ G-Man: Capisci che il tuo articolo (2) rende questa risposta una risposta precisa all'OP?
Eric Towers,

No, non lo capisco. Per favore spiegamelo.
G-Man dice "Ripristina Monica" il

4
Non ti sto seguendo. La domanda non richiede esempi pratici di tutti i comandi incorporati in bash; chiede esempi di exec- e il fatto che killsia un builtin non ha davvero nulla a che fare con il execbuiltin.
G-Man dice "Ripristina Monica" il

1
Ho appena letto il tuo aggiornamento alla tua risposta. (1) Indovina un po '? Se la tabella dei processi è piena, anche la sostituzione dei comandi (ad es. `which kill`) Non funzionerà. (2) A proposito, il $(…)modulo è consigliato sul `…`modulo. (3) Ma non c'è nulla di pericoloso nell'indovinare la directory. Se digiti per errore exec /binn/kill, riceverai semplicemente un messaggio di errore e la tua shell non andrà via. (4) Ma non devi nemmeno preoccuparti di quale directory si killtrova.  execUsa $PATH, proprio come i normali comandi, quindi exec kill …funziona (supponendo che tu abbia /binnel tuo percorso di ricerca).
G-Man dice "Ripristina Monica" il

1
  • Questo è simile all'esempio di Bruce sulla necessità di conoscere il PID di un processo:

    (cmdpid = $ BASHPID; (sleep 300; uccidi "$ cmdpid") ed esegui un comando di lunga durata )

    in cui tu

    1. Avvia una subshell (l'esterno (e )),
    2. Scopri il PID della subshell. ( $$ti darà il PID della shell principale.)
    3. Scollegare una sotto-shell che uccide il processo dopo un timeout e
    4. Eseguire un comando nel processo della subshell creato nel passaggio 1.

    Questo funzionerà long-running-command, ma solo per un periodo di tempo predeterminato e limitato. 

  • Questo è un po 'frivolo, ma, se decidi di voler essere root (o qualche altro utente) per il resto della sessione di accesso, potresti farlo exec su.

    In realtà, posso immaginare uno scenario in cui questo sarebbe davvero utile. Supponiamo che tu abbia effettuato l'accesso a un sistema remoto e, per qualche motivo, si sia verificato un problema con l'interruzione della connessione e l'avvio di una nuova connessione. Ad esempio, supponiamo che il sistema remoto abbia un firewall che segue una pianificazione. Ti è stato permesso di connetterti quando lo hai fatto e le connessioni stabilite non vengono chiuse, ma al momento non vengono accettate nuove connessioni.

    Hai fatto quello che volevi fare e sei pronto per uscire. Il tuo amico Bob è nella stanza con te e vuole fare un po 'di lavoro sul sistema remoto, ma non sarà in grado di connettersi. Quindi, si digita exec su - bobe, quando viene visualizzato il prompt della password, girare la workstation su di lui. Ora non esiste alcun processo con il tuo UID (a meno che tu non abbia eseguito qualcosa in background), quindi Bob non sarà in grado di scherzare con i tuoi file. Avrà effettivamente assunto il controllo della tua connessione (con il tuo consenso e la tua collaborazione).

    Appunti:

    • Ovviamente questo non funzionerà se non ti è permesso di correre su.
    • Verrà registrato, quindi potrebbe essere necessario spiegare le tue motivazioni a qualcuno. Poiché si sta aggirando la politica (la pianificazione del firewall), è possibile che si verifichino problemi.
    • Non garantisco che sia sicuro al 100%. Ad esempio, whoprobabilmente mostrerà comunque il tuo nome. È concepibile che un programma (scritto male) lo userà per pensare che tu sia Bob e che gli dia accesso alle tue risorse.
    • Se il sistema esegue il controllo, le azioni di Bob potrebbero essere controllate a tuo nome.

Si noti che in pratica nella maggior parte delle shell, (a;b)è già lo stesso che (a;exec b)le shell ottimizzano il fork per l'ultimo comando in una sottoshell. Le uniche eccezioni sembrano essere bashe mksh. L'utilizzo execaiuta a garantirlo.
Stéphane Chazelas,
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.