Por que um loop while pára após ser suspenso?

10

Por que usar o bash e suspender um loop while, o loop pára após ser retomado? Exemplo curto abaixo.

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

Estou familiarizado com os sinais, e acredito que esse seja o comportamento natural do bash aqui, mas gostaria de entender melhor por que ele se comporta dessa maneira particular.

    
por bkzland 26.11.2015 / 14:50

2 respostas

10

Isso parece um bug em vários shells, e funciona como esperado com ksh93 e zsh .

Antecedentes:

A maioria das shells parece rodar o loop while dentro do shell principal e

Bourne Shell suspende todo o shell se você digitar ^ Z com um shell que não seja de login

bash suspende apenas o sleep e, em seguida, deixa o loop while em favor da impressão de um novo prompt de shell

dash torna este comando inaceitável

Com o ksh93 , as coisas funcionam de maneira muito diferente:

ksh93 faz o mesmo, enquanto o comando é iniciado na primeira vez, mas como sleep é um buitin em ksh93, ksh93 tem um manipulador que faz com que o loop while seja removido do shell principal e, em seguida, suspender no momento em que você digita ^ Z.

Se você digitar ksh93 mais tarde, digite fg , o filho bifurcado que ainda executa o loop continuará.

Você vê a principal diferença ao comparar as mensagens do jobcontrol do bash e do ksh93:

bash relatórios:

[1]+ Stopped sleep 1

mas relatórios ksh93 :

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

zsh se comporta de maneira semelhante a ksh93

Com os dois shells, você tem um único processo (o shell principal), desde que você não digite ^ Z e dois processos de shell depois que você digitou ^ Z.

    
por 26.11.2015 / 16:02
3

Eu escrevi um dos co-autores do Bash sobre o assunto, e aqui está sua resposta:

It's not really a bug, but it is certainly a caveat.

The idea here is that you suspend processes, which are a different unit of granularity than shell commands. When a process is suspended, it returns to the shell (with a non-zero status, which has consequences when you, say, stop a process that's the loop test), which has a choice: it can break out of or continue the loop, leaving the stopped process behind. Bash chooses -- and has always chosen -- to break out of loops when a job is stopped. Continuing the loop is rarely what you want.

Some other shells do things like fork a copy of the shell when a process gets suspended due to SIGTSTP, and stop that process. Bash hasn't ever done that -- it seems more complicated than the benefit warrants -- but if someone wants to submit that code as a patch, I'd take a look at incorporating the changes.

Portanto, se alguém quiser enviar um patch, use os endereços de e-mail encontrados nas páginas man.

    
por 26.08.2018 / 06:30