Ao digitar ctrl-c em um terminal, por que o job em primeiro plano não é terminado até que seja concluído? [fechadas]

0

Para entender

If Bash is waiting for a command to complete and receives a signal for which a trap has been set, the trap will not be executed until the command completes.

When Bash is waiting for an asynchronous command via the wait builtin, the reception of a signal for which a trap has been set will cause the wait builtin to return immediately with an exit status greater than 128, immediately after which the trap is executed.

do manual do Bash, Eu corro o seguinte:

  1. Nos meus dois exemplos, SIGINT (enviado com Ctrl-C) termina trabalho em primeiro plano (o primeiro caso na cotação) e um trabalho em segundo plano (o segundo caso da citação) ambos imediatamente, sem esperar por eles para completar.

    A primeira frase da citação significa que, se o Bash estiver executando um trabalho de primeiro plano e recebe sinal SIGINT , a armadilha do sinal SIGINT , quando definido, será executado até que o comando seja concluído? Se sim, por que no meu primeiro exemplo, ctrl-C faz o primeiro plano o trabalho existe imediatamente antes que ele possa ser concluído?

    $ sleep 10000  # a foreground job
    ^C
    
    
    $ sleep 10000 & # a background job
    [1] 21219
    $ wait 21219
    ^C
    $ echo $?
    130
    
  2. O que "um sinal para o qual uma armadilha foi definida" significa,

    • um sinal arg cuja armadilha foi especificada via trap arg sigspec , ou

    • um sinal que não é ignorado, ou

    • um sinal cuja armadilha não é a padrão?

    Nos exemplos da minha parte 1, eu não configurei uma armadilha para o SIGINT, então o sinal tem manipulador padrão (que sai de qualquer loop de execução). É um sinal tendo seu manipulador padrão considerado como uma armadilha que tem foi definido?

  3. Eu configurei uma armadilha para SIGINT , mas ctrl-C fará o seguinte saída de comando antes de concluir. Então é contrário ao primeiro frase na minha citação?

    $ trap "echo You hit control-C!" INT
    $ bash -c 'sleep 10; echo "$?"'
    ^C
    $
    

    Antes de definir o trap para SIGINT , ctrl-C também fará o mesmo comando sair antes de concluir. Então é contrário ao primeiro frase na minha citação?

    $ bash -c 'sleep 10; echo "$?"'
    ^C
    
  4. Você poderia dar alguns exemplos para explicar o que as duas frases as citações significam?

Obrigado.

    
por Tim 08.08.2017 / 12:10

1 resposta

5

What does "a signal for which a trap has been set" mean?

Esse é um sinal para o qual um manipulador foi definido (com trap 'handling code' SIG ) onde o código de manipulação não está vazio, pois isso faria com que o sinal fosse ignorado.

Portanto, os sinais que têm sua disposição padrão não são sinais para os quais uma armadilha foi definida. Algumas dessas citações em sua postagem também se aplicam a sinais que têm sua disposição padrão, embora obviamente não seja a parte sobre executar a armadilha , já que nenhuma armadilha foi definida para eles.

O manual fala sobre a entrega de sinal para o shell , não para os comandos que você executa a partir desse shell.

1.

If Bash is waiting for a command to complete and receives a signal for which a trap has been set, the trap will not be executed until the command completes.

(1)

why in my first example, does ctrl-C make the foreground job exit immediately before it can complete

Se você executar sleep 10 no prompt de um shell interativo , o shell colocará esse trabalho no primeiro plano (por meio de um ioctl() no dispositivo tty que informa à disciplina de linha de terminal qual grupo de processos é o primeiro plano), então somente sleep obterá uma SIGINT em ^C e o shell interativo não , portanto não é útil testar esse comportamento .

  • O shell pai, como é interativo, não receberá o SIGINT, pois o processo não está no grupo de processos em primeiro plano.

  • Cada comando é livre para manipular sinais como bem entenderem. sleep não faz nada especialmente com o SIGINT, portanto, obterá a disposição padrão (terminar), a menos que o SIGINT esteja sendo ignorado na inicialização.

(2) Se você executar sleep 10 em um shell não interativo ,

bash -c 'sleep 10; echo "$?"'

O% não-interativo bash shell e sleep receberão o SIGINT quando você pressionar Ctrl-C.

Se bash sair imediatamente, ele poderá deixar o comando sleep em execução em segundo plano se ignorar ou manipular o sinal SIGINT. Então, ao invés disso,

  • bash como a maioria dos outros shells, bloqueia a recepção de sinais (pelo menos alguns sinais) ao aguardar comandos.
  • A entrega é retomada depois que o comando sai (no qual as traps são executadas). Isso também evita que comandos em traps sejam executados simultaneamente com outros comandos.

Nesse exemplo acima, sleep morrerá no SIGINT, portanto, bash não demora muito para manipular seu próprio SIGINT (aqui para morrer, pois não adicionei um trap no SIGINT).

(3) quando você pressiona Ctrl + C enquanto executa o shell não interativo:

bash -c 'sh -c "trap \"\" INT; sleep 3"; echo "$?"'

(sem trap no SIGINT) bash não é eliminado pelo SIGINT. bash , como alguns outros shells tratam SIGINT e SIGQUIT especialmente. Eles implementam o comportamento espera e saída cooperativa descrito no link (e é conhecido por causar alguns aborrecimentos como os scripts chamando o SIGINT manipulando comandos que não podem ser interrompidos com ^C )

(4) Para testar adequadamente, você deve executar um bash não interativo que possui um conjunto de interceptações SIGINT e chamar um comando que não morra logo no SIGINT como:

bash -c 'trap "echo Ouch" INT; sh -c "trap \"\" INT; sleep 3"'

bash está aguardando sh que (juntamente com sleep ) SIGINT foi ignorado (por causa do trap "" INT ), portanto, o SIGINT não eliminará sleep nem sh . bash não ignora o SIGINT, mas seu tratamento é adiado até que sh retorne. Você verá Ouch sendo exibido, não em Ctrl + C , mas após sleep e sh terem terminado normalmente.

Observe que o comando trap define um trap para um sinal para o mesmo shell no qual ele é executado. Então, quando o comando trap é executado fora do shell não interativo e no shell pai,

$ trap "echo You hit control-C!" INT
$ bash -c 'sleep 10; echo "$?"'
^C
$

os comandos não interativo bash e sleep não herdarão esse trap do shell pai. Os manipuladores de sinal são perdidos ao executar um comando diferente ( execve() apaga todo o espaço de endereço do processo, incluindo o código do manipulador). Após execve() , os sinais que tinham um manipulador definido revertem para a disposição padrão, aqueles que foram ignorados permanecem ignorados. Além disso, na maioria dos shells, trap s também são resetados em sub-shells.

2.

When Bash is waiting for an asynchronous command via the wait builtin, the reception of a signal for which a trap has been set will cause the wait builtin to return immediately with an exit status greater than 128, immediately after which the trap is executed.

Ao usar wait explicitamente , wait é interrompido por qualquer sinal que tenha um conjunto de interceptações (e, obviamente, também aquelas que matam o shell completamente).

Isso torna difícil obter o status de saída de um comando de maneira confiável quando há sinais retidos :

$ bash -c 'trap "echo Ouch" INT; sh -c "trap \"\" INT; sleep 10" & wait "$!"; echo "$?"'
^COuch
130

Nesse caso, sleep e sh não foram mortos pelo SIGINT (já que eles o ignoram). Ainda wait retorna com um status de saída 130 porque um sinal (SIGINT) foi recebido enquanto aguardava sh . Você precisaria repetir o wait "$!" até que sh realmente terminasse para obter o status de saída de sh .

    
por 08.08.2017 / 13:13

Tags