Vuoi migliorare questa domanda? Aggiungi dettagli e chiarisci il problema modificando questo post.
Chiuso 3 anni fa.
Migliora questa domanda
Per capire
Se Bash è in attesa del completamento di un comando e riceve un segnale per
che è stata impostata una trap, la trap non verrà eseguita fino al completamento del comando
.
Quando Bash è in attesa di un comando asincrono tramite il wait integrato ,
la ricezione di un segnale per il quale è stata impostata una trap farà tornare immediatamente l'attesa
incorporata con uno stato di uscita maggiore di
128, subito dopo la quale la trap viene eseguita.
dal manuale di Bash,
eseguo quanto segue:
-
Nei miei due esempi, SIGINT (inviato con Ctrl-C) termina un
lavoro in primo piano (il primo caso nella citazione) e un lavoro in background
(il secondo caso nella citazione) entrambi immediatamente, senza attendere per
completarli.La prima frase della citazione significa che se Bash sta eseguendo un processo in
in primo piano e riceve il segnaleSIGINT
, la trappola del segnaleSIGINT
, quando impostato, verrà eseguito fino al completamento del comando?
Se sì, perché nel mio primo esempio,ctrl-C
fare in modo che il lavoro in primo piano
esista immediatamente prima che possa essere completato?$ sleep 10000 # a foreground job ^C $ sleep 10000 & # a background job [1] 21219 $ wait 21219 ^C $ echo $? 130
-
Che cosa significa "un segnale per il quale è stata tesa una trappola" significa,
-
un segnale
arg
il cui trap è stato specificato tramitetrap arg sigspec
o -
un segnale che non viene ignorato, oppure
-
un segnale la cui trappola non è quella di default?
Negli esempi della mia parte 1, non ho impostato una trap per SIGINT, quindi il segnale ha il suo
gestore predefinito (che interrompe qualsiasi ciclo di esecuzione). È un
segnale con il suo gestore predefinito considerata una trappola che
è stata tesa? -
-
Ho creato una trappola per
SIGINT
, mactrl-C
farà uscire il comando
seguente prima del completamento. Quindi è contrario alla prima
frase nella mia citazione?$ trap "echo You hit control-C!" INT $ bash -c 'sleep 10; echo "$?"' ^C $
Prima di impostare la trappola per
SIGINT
,ctrl-C
farà uscire anche lo
stesso comando prima del completamento. Quindi è contrario alla prima
frase nella mia citazione?$ bash -c 'sleep 10; echo "$?"' ^C
-
Potresti fornire alcuni esempi per spiegare cosa significano le due frasi nella
citazione?
Grazie.
Risposta accettata:
Che cosa significa "un segnale per il quale è stata predisposta una trappola"?
Questo è un segnale per il quale è stato definito un handler (con trap 'handling code' SIG
) dove il codice di gestione non è vuoto in quanto ciò comporterebbe l'ignoranza del segnale.
Quindi i segnali che hanno la loro disposizione predefinita non sono segnali per i quali è stata tesa una trappola.
Alcune delle citazioni nel tuo post si applicano anche ai segnali che hanno la loro disposizione predefinita, sebbene ovviamente non la parte relativa all'esecuzione del trappola , poiché per loro non è stata definita alcuna trappola.
Il manuale parla della consegna del segnale alla shell , non ai comandi che esegui da quella shell.
1.
Se Bash è in attesa del completamento di un comando e riceve un segnale per il quale è stata impostata una trap, la trap non verrà eseguita fino al completamento del comando.
(1)
perché nel mio primo esempio, ctrl-C fa uscire il lavoro in primo piano immediatamente prima che possa essere completato
Se esegui sleep 10
al prompt di una shell interattiva , la shell metterà quel lavoro in primo piano (attraverso un ioctl()
sul dispositivo tty che dice alla disciplina della linea terminale quale gruppo di processi è quello in primo piano), quindi solo sleep
otterrà un SIGINT su ^C
e la shell interattiva non lo farà , quindi non è utile testare tale comportamento.
-
La shell madre, poiché è interattiva, non riceverà il SIGINT poiché il suo processo non è nel gruppo di processi in primo piano.
-
Ogni comando è libero di gestire i segnali a proprio piacimento.
sleep
non fa nulla in particolare con SIGINT, quindi otterrà la disposizione predefinita (termina) a meno che SIGINT non sia stato ignorato all'avvio.
(2) Se esegui sleep 10
in una shell non interattiva ,
bash -c 'sleep 10; echo "$?"'
Entrambi i bash
non interattivi shell e sleep
riceverà il SIGINT quando premi Ctrl-C.
Se bash
uscito subito, potrebbe lasciare il sleep
comando in esecuzione non presidiato in background se è capitato di ignorare o gestire il segnale SIGINT. Quindi, invece,
bash
come la maggior parte delle altre shell, blocchi la ricezione di segnali (almeno alcuni segnali) in attesa di comandi.- La consegna riprende dopo l'uscita del comando (su cui vengono eseguite le trap). Ciò evita anche che i comandi nelle trap vengano eseguiti contemporaneamente ad altri comandi.
Nell'esempio sopra, sleep
morirà su SIGINT, quindi bash
non deve aspettare molto per gestire il proprio SIGINT (qui per morire perché non ho aggiunto una trap
su SIGINT).
(3) quando si preme Ctrl+C durante l'esecuzione della shell non interattiva:
bash -c 'sh -c "trap "" INT; sleep 3"; echo "$?"'
(senza trap
su SIGINT) bash
non viene ucciso dal SIGINT. bash
, come poche altre shell trattano SIGINT e SIGQUIT in modo speciale. Implementano l'attesa e l'uscita cooperativa comportamento descritto su https://www.cons.org/cracauer/sigint.html (ed è noto per causare alcuni fastidi come gli script che chiamano SIGINT comandi di gestione che non possono essere interrotti con ^C
)
(4) Per testare correttamente, dovresti eseguire un bash
non interattivo che ha impostato la trappola SIGINT e chiama un comando che non muore subito su SIGINT come:
bash -c 'trap "echo Ouch" INT; sh -c "trap "" INT; sleep 3"'
bash
sta aspettando sh
che ha (insieme a sleep
) SIGINT ignorato (a causa del trap "" INT
), quindi SIGINT non ucciderà sleep
né sh
. bash
non ignora SIGINT, ma la sua gestione è differita fino a sh
ritorna. Vedi Ouch
visualizzato, non su Ctrl+C , ma dopo sleep
e sh
sono terminate normalmente.
Nota che la trap
comando imposta una trappola per un segnale per la stessa shell in cui viene eseguito. Quindi quando la trap
il comando viene eseguito al di fuori della shell non interattiva e nella shell padre,
$ trap "echo You hit control-C!" INT $ bash -c 'sleep 10; echo "$?"' ^C $
il bash
non interattivo e sleep
i comandi non erediteranno quel trap
dalla shell madre. I gestori di segnale vengono persi durante l'esecuzione di un comando diverso (execve()
cancella l'intero spazio degli indirizzi del processo incluso il codice del gestore). Su execve()
, i segnali che avevano un gestore definito ripristinano la disposizione predefinita, quelli che erano stati ignorati rimangono ignorati.
Inoltre, nella maggior parte delle shell, trap
Le s vengono reimpostate anche nelle sottoshell.
2.
Quando Bash è in attesa di un comando asincrono tramite il wait integrato , la ricezione di un segnale per il quale è stata impostata una trap farà ritornare immediatamente l'attesa incorporata con uno stato di uscita maggiore di 128, subito dopo la quale la trap viene eseguita.
Quando usi wait
esplicitamente , wait
viene interrotto da qualsiasi segnale che abbia una trappola impostata (e ovviamente anche quelli che uccidono del tutto la shell).
Ciò rende difficile ottenere lo stato di uscita di un comando in modo affidabile quando sono presenti segnali intrappolati :
$ bash -c 'trap "echo Ouch" INT; sh -c "trap "" INT; sleep 10" & wait "$!"; echo "$?"'
^COuch
130
In tal caso, sleep
e sh
non sono stati uccisi dal SIGINT (poiché lo ignorano). Ancora wait
ritorna con un 130
stato di uscita perché è stato ricevuto un segnale (SIGINT) mentre era in attesa di sh
. Dovresti ripetere wait "$!"
fino a sh
termina davvero per ottenere sh
stato di uscita.