GNU/Linux >> Linux Esercitazione >  >> Linux

Quando si digita Ctrl-c in un terminale, perché il lavoro in primo piano non viene terminato fino al completamento?

Chiuso . Questa domanda ha bisogno di dettagli o chiarezza. Attualmente non accetta risposte.

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:

  1. 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 segnale SIGINT , la trappola del segnale
    SIGINT , 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
    
  2. Che cosa significa "un segnale per il quale è stata tesa una trappola" significa,

    • un segnale arg il cui trap è stato specificato tramite trap 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?

  3. Ho creato una trappola per SIGINT , ma ctrl-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
    
  4. 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.

Correlati:Linux:aumentare il volume di un video MKV dal terminale Linux?

(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à sleepsh . 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).

Correlati:come formattare rapidamente una partizione in un filesystem?

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.


Linux
  1. Perché più istanze di Mate-terminal hanno lo stesso Pid?

  2. chiama una funzione quando il programma è finito con ctrl c

  3. Quando è utile setsid() o perché abbiamo bisogno di raggruppare i processi in Linux?

  4. perché un ciclo while bash non esce durante il piping al sottocomando terminato?

  5. Perché clang genera testo incomprensibile quando viene reindirizzato?

Perché amo ancora Alpine per la posta elettronica sul terminale Linux

Bash-insulter – Uno script che insulta l'utente quando digita un comando sbagliato

Qual è il modo corretto per chiudere la mia applicazione PyQt quando viene uccisa dalla console (Ctrl-C)?

Quando viene gestito un segnale e perché alcune informazioni si bloccano?

Cosa determina esattamente se un lavoro in background viene interrotto quando la shell viene chiusa o terminata?

Perché non riesco a scorrere nel terminale?