Perché un ciclo while si interrompe dopo essere stato sospeso?


10

Perché usando bash e sospendendo un ciclo while, il ciclo si interrompe dopo essere stato ripreso? Breve esempio di seguito.

$ while true; do echo .; sleep 1; done
.
.
^Z
[1]+  Stopped                 sleep 1
$ fg
sleep 1
$

Ho familiarità con i segnali e immagino che questo possa essere il comportamento naturale di bash qui, ma mi piacerebbe capire meglio perché si comporta in questo modo particolare.


perché deve gestire un interrupt e deve rispecchiarlo accuratamente in $?ritorno, e così truenon è allora true. probabilmente. credo.
mikeserv,

1
Spero che questo commento non venga segnalato, ma risponderò alla tua domanda con un'altra domanda, in stile koan Unix: "Perché uno studente smette di combattere nel parco giochi dopo essere stato sospeso?" La risposta è, perché non è più nel parco giochi dove ha la capacità di iniziare combattimenti. Pertanto, il comportamento in questione è stato semplicemente interrotto.
rubynorails,

Si interrompe il comando, il ciclo è interrotto. Quindi riprendi il singolo comando sleep 1, non il loop.
123,

Risposte:


10

Sembra un bug in diverse shell, funziona come previsto con ksh93 e zsh .

Sfondo:

La maggior parte delle shell sembrano eseguire il ciclo while all'interno della shell principale e

Bourne Shell sospende l'intera shell se si digita ^ Z con una shell non di accesso

bash sospende solo il sleepe quindi lascia il ciclo while in favore della stampa di un nuovo prompt della shell

dash rende questo comando insostenibile

Con ksh93 , le cose funzionano in modo molto diverso:

ksh93 fa lo stesso, mentre il comando viene avviato la prima volta, ma come sleepè un buitin in ksh93, ksh93 ha un gestore che fa in modo che il ciclo while esegua il fork della shell principale e quindi la sospenda nel momento in cui si digita ^ Z.

Se si digita ksh93 in seguito fg, il figlio biforcuto che esegue ancora il ciclo continua.

Si vede la differenza principale quando si confrontano i messaggi jobcontrol da bash e ksh93:

bash segnala:

[1]+ Stopped sleep 1

ma ksh93 riporta:

^Z[1] + Stopped while true; do echo .; sleep 1; done

zsh si comporta in modo simile a ksh93

Con entrambe le shell, hai un singolo processo (la shell principale) purché non digiti ^ Z e due processi di shell dopo aver digitato ^ Z.


in dashrealtà non finisce per gestire il segnale quando termina il loop? nel [d]?ashcodice sorgente ci sono tutte queste macro per INTON e INTOFF sparse ovunque, e in genere i segnali ricevuti mentre in uno stato INTOFF sono realmente gestiti su (o intorno a) INTON . comunque, sono solo curioso perché penso che tu lo sappia meglio - è un'ottima risposta. grazie.
Mikeserv,

Uso raramente dash e recentemente l'ho preso e compilato per confronti di prestazioni con bash, ksh93 e la mia Bourne Shell. Durante questi test, ho scoperto che il trattino sembra essere principalmente veloce perché non include il supporto per i caratteri multi byte. Un singolo sleep 100può essere sospeso e ripreso dash, quindi sembra che sia a dashconoscenza dei problemi in questo comando e disabilita selettivamente il controllo del lavoro.
schily,

quindi, nei tuoi test, sei stato in grado di eguagliare dashle prestazioni in altre shell rilasciando l'elaborazione multibyte? e sì, dashsupporta il controllo del lavoro, ma lo standard dice che una shell interattiva dovrebbe ignorare il TSTP e che l'esecuzione di un ciclo while nella shell corrente su un terminale interattivo non è meno una shell interattiva rispetto a qualsiasi altra.
mikeserv,

Non ho provato esattamente questo, ma ho potuto vedere che mentre il dash consuma più tempo della CPU del sistema rispetto a ksh93 o Bourne Shell (principalmente perché emette più fork () chiamate), utilizza meno tempo della CPU dell'utente e questo si traduce in un totale simile Tempo di CPU rispetto alla mia versione di Bourne Shell. Dal tentativo di ridurre il tempo della CPU dell'utente nella Bourne Shell, so che la maggior parte di questo tempo viene impiegato in conversioni multibyte.
schily,

4

Ho scritto uno dei coautori di Bash sull'argomento, ed ecco la sua risposta:

Non è davvero un bug, ma è certamente un avvertimento.

L'idea qui è di sospendere i processi, che sono un'unità di granularità diversa rispetto ai comandi della shell. Quando un processo è sospeso, ritorna alla shell (con uno stato diverso da zero, che ha conseguenze quando, per esempio, interrompi un processo che è il test del ciclo), che ha una scelta: può uscire o continuare il ciclo , lasciando indietro il processo interrotto. Bash sceglie - e ha sempre scelto - di interrompere i cicli quando un lavoro viene interrotto. Continuare il ciclo è raramente quello che vuoi.

Alcune altre shell eseguono operazioni come fork di una copia della shell quando un processo viene sospeso a causa di SIGTSTP e interrompono tale processo. Bash non lo ha mai fatto - sembra più complicato dei vantaggi in termini di benefici - ma se qualcuno vuole inviare quel codice come patch, darei un'occhiata all'incorporazione delle modifiche.

Quindi, se qualcuno vuole inviare una patch, usa gli indirizzi email trovati nelle pagine man.

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.