SIGINT que controla diferenças entre o bash 3 e 4

2

Eu tenho um script que funciona muito bem no bash 4.3, mas me dá um comportamento inesperado com o bash 3.2. Aqui está uma versão simplificada:

set -o errexit -o pipefail

task() {
    local name=${1}
    local duration=${2}
    trap 'echo "[${SECONDS} secs] ${name}: SIGINT"; exit 255' INT
    echo "[${SECONDS} secs] ${name}: Running"
    sleep "${duration}"
    echo "[${SECONDS} secs] ${name}: Done"
}

trap 'echo "[${SECONDS} secs] SIGINT"; exit 255' INT
task 'Task 1' 5 &
task 'Task 2' 5 &
wait
echo "[${SECONDS} secs] Done"

Aqui está a saída quando executado com o bash 4.3 (4.3.42 (1) -release) depois de CTRL-C'ing dois segundos dentro dele:

[0 secs] Task 1: Running
[0 secs] Task 2: Running
^C[2 secs] SIGINT
[2 secs] Task 2: SIGINT
[2 secs] Task 1: SIGINT
prompt>

Mesma coisa, mas com o bash 3.2 (3.2.57 (1) -release):

[0 secs] Task 1: Running
[0 secs] Task 2: Running
^C[2 secs] SIGINT
prompt> [5 secs] Task 2: Done
[5 secs] Task 1: Done

Existem problemas conhecidos que impedem o script acima de funcionar corretamente no bash 3.2? Existem soluções alternativas?

Aqui estão algumas coisas que eu tentei:

  • Nenhum manipulador de sinal no pai:

    # bash 4.3
    [0 secs] Task 1: Running
    [0 secs] Task 2: Running
    ^C[2 secs] Task 2: SIGINT
    [2 secs] Task 1: SIGINT
    prompt>
    
    # bash 3.2
    [0 secs] Task 1: Running
    [0 secs] Task 2: Running
    ^C
    prompt> [5 secs] Task 2: Done
    [5 secs] Task 1: Done
    
  • Nenhum manipulador de sinal:

    # bash 4.3
    [0 secs] Task 1: Running
    [0 secs] Task 2: Running
    ^C
    prompt>
    
    # bash 3.2
    [0 secs] Task 1: Running
    [0 secs] Task 2: Running
    ^C
    prompt> [5 secs] Task 2: Done
    [5 secs] Task 1: Done
    
  • Manipulador de sinais no pai que mata o grupo de processos com SIGINT ( kill -INT -- -$$ ):

    [0 secs] Task 1: Running
    [0 secs] Task 2: Running
    ^C[2 secs] SIGINT
    [2 secs] Task 2: SIGINT
    [2 secs] Task 1: SIGINT
    prompt>
    
    [0 secs] Task 1: Running
    [0 secs] Task 2: Running
    ^C[2 secs] SIGINT
    prompt> [5 secs] Task 2: Done
    [5 secs] Task 1: Done
    
  • Manipulador de sinais no pai que mata o grupo de processos com SIGTERM (tarefas interceptam SIGTERM):

    # bash 4.3
    [0 secs] Task 1: Running
    [0 secs] Task 2: Running
    ^C[2 secs] SIGINT
    [2]    92813 terminated  bash minimal_example.sh
    prompt>
    
    # bash 3.2
    [0 secs] Task 1: Running
    [0 secs] Task 2: Running
    ^C[2 secs] SIGINT
    Terminated: 15
    Terminated: 15
    [2 secs] Task 2: SIGTERM
    [2 secs] Task 1: SIGTERM
    [1]    92836 terminated  /bin/bash minimal_example.sh
    prompt>
    

O último é o mais próximo de funcionar corretamente em 3.2, mas esse mesmo código se comporta de maneira diferente em 4.3.

    
por Matt Tardiff 26.01.2016 / 05:36

1 resposta

2

Pode ser que você seja vítima de um problema bash bem conhecido que atinge com frequência make usuários.

Eu ainda não verifiquei o bash 4, mas bash 3 incorretamente faz o jobcontrol dentro dos scripts. Isso geralmente faz com que os makefiles que contêm um loop sobre vários subdiretórios não sejam facilmente eliminados por ^C , porque os subprocessos são executados em grupos de processos separados, mesmo que esses comandos não sejam interativos.

smake inclui uma solução alternativa para /bin/sh sendo bash e encaminha explicitamente SIGINT para o grupo procress do comando atualmente em execução. Mas este é um software escrito em C .

O mesmo não pode ser implementado com shells usuais em scripts, pois não há um comando UNIX padrão para recuperar o grupo de processos de um filho.

    
por 26.01.2016 / 14:49