GNU/Linux >> Linux Esercitazione >  >> Linux

Bash:perché lo script genitore non termina su SIGINT quando lo script figlio intercetta SIGINT?

Nuova risposta:

Questa domanda è molto più interessante di quanto inizialmente sospettassi. La risposta è essenzialmente data qui:

Cosa succede a un SIGINT (^C) quando viene inviato a uno script perl contenente bambini?

Ecco il bocconcino pertinente. Mi rendo conto che non stai usando Perl, ma presumo che Bash stia usando la convenzione di C.

La funzione di sistema incorporata di Perl funziona esattamente come la funzione C system(3) della libreria C standard per quanto riguarda i segnali. piuttosto che quello chiamato da esso, IGNORERÀ qualsiasi SIGINT e SIGQUIT mentre i bambini corrono.

Questa spiegazione è la migliore che ho visto sulle varie scelte che si possono fare. Dice anche che Bash adotta l'approccio WCE. Cioè, quando un processo genitore riceve SIGINT, attende fino a quando il suo processo figlio ritorna. Se quel processo gestito è uscito da un SIGINT, esce anche con SIGINT. Se il figlio è uscito in qualsiasi altro modo, ignora SIGINT.

C'è anche un modo in cui la shell chiamante può dire se il programma chiamato è terminato su SIGINT e se ha ignorato SIGINT (o lo ha usato per altri scopi). Come nel modo WUE, la shell attende che il bambino completi. Calcola se il programma è stato terminato su SIGINT e, in tal caso, interrompe lo script. Se il programma è uscito in qualsiasi altro modo, lo script verrà continuato. Chiamerò il modo di fare le cose "WCE" (per "attesa e uscita cooperativa") per il resto di questo documento.

Non riesco a trovare un riferimento a questo nella pagina man di Bash, ma continuerò a cercare nei documenti informativi. Ma sono sicuro al 99% che questa sia la risposta corretta.

Risposta precedente:

Uno stato di uscita diverso da zero da un comando in uno script Bash non termina il programma. Se fai un echo $? dopo ./script2.sh mostrerà 130. Puoi terminare lo script usando set -e come suggerisce phs.

$ help set
...
-e  Exit immediately if a command exits with a non-zero status.

La seconda parte della risposta aggiornata di @seanmcl è corretta e il collegamento a http://www.cons.org/cracauer/sigint.html è davvero utile da leggere attentamente.

Da quel link, "Non puoi 'falsificare' lo stato di uscita corretto con un exit(3) con un valore numerico speciale, anche se cerchi il valore numerico per il tuo sistema ". In effetti, questo è ciò che viene tentato nello script2.sh di @Hermann Speiche.

Una risposta è modificare il gestore di funzione in script2.sh come segue:

function handler {
  # ... do stuff ...
  trap INT
  kill -2 $$
}

Ciò rimuove efficacemente il gestore del segnale e "rilancia" il SIGINT, causando l'uscita del processo bash con i flag appropriati in modo tale che il suo processo bash padre gestisca correttamente il SIGINT che gli è stato originariamente inviato. In questo modo, usando set -e o qualsiasi altro hack non è effettivamente richiesto.

Vale anche la pena notare che se hai un eseguibile che si comporta in modo errato quando viene inviato un SIGINT (non è conforme a "Come essere un programma appropriato" nel link sopra, ad esempio esce con un normale codice di ritorno), un modo di aggirare questo problema consiste nel racchiudere la chiamata a quel processo con uno script come il seguente:

#!/bin/bash

function handler {
  trap INT
  kill -2 $$
}

trap handler INT
badprocess "[email protected]"

Linux
  1. Perché il Pgid dei processi figlio non è il Pid del genitore?

  2. Perché la sostituzione del processo Bash non funziona con alcuni comandi?

  3. Perché lo script Bash non si chiude dopo l'esecuzione?

  4. Perché non posso usare Cd in uno script Bash??

  5. Perché il file di traduzione Bash non contiene tutti i testi di errore?

Perché il documento Parent Shell Here non funziona per il sottocomando in Dash ma Bash funziona?

Perché `esce &` non funziona?

Qualsiasi modo per uscire dallo script bash, ma non uscire dal terminale

Cosa significa set -e in uno script bash?

Genera errore in uno script Bash

perché eliminare la cronologia di bash non è sufficiente?