Ctrl-C com dois comandos simultâneos no bash

11

Eu quero executar dois comandos simultaneamente no bash em uma máquina Linux. Portanto, no meu script ./execute.sh bash eu coloco:

command 1 & command 2
echo "done"

No entanto, quando eu quero parar o script bash e teclar Ctrl + C , somente o segundo comando é parado. O primeiro comando continua em execução. Como posso ter certeza de que o script bash completo está parado? Ou em qualquer caso, como eu paro os dois comandos? Porque neste caso, não importa quantas vezes eu pressione Ctrl + C , o comando continua rodando e eu sou forçado a fechar o terminal.

    
por maero21 01.01.2014 / 14:54

4 respostas

14

Se você digitar

command 1 & command 2

isso é igual a

command 1 &
command 2

i.e. isso executará o primeiro comando em segundo plano e, em seguida, executará o segundo comando em primeiro plano. Isso significa que o echo "done" é impresso depois que command 2 terminar, mesmo se command 1 ainda estiver em execução.

Você provavelmente quer

command 1 &
command 2 &
wait
echo "done"

Isso executará os dois comandos em segundo plano e aguardará a conclusão de ambos.

Se você pressionar CTRL-C, somente o sinal SIGINT será enviado para o processo de primeiro plano, ou seja, command 2 na sua versão ou wait na minha versão.

Sugiro configurar uma armadilha como esta:

#!/bin/bash

trap killgroup SIGINT

killgroup(){
  echo killing...
  kill 0
}

loop(){
  echo $1
  sleep $1
  loop $1
}

loop 1 &
loop 2 &
wait

Com o trap o sinal SIGINT produzido pelo CTRL-C é capturado e substituído pela função killgroup , que mata todos esses processos.

    
por 01.01.2014 / 15:15
5

Ao colocar um comando em segundo plano a partir de um script, o PID não é exibido na tela. A variável incorporada $! armazena o PID do último processo para que você possa capturar o PID do comando1 usando-o.

command1 &
echo $!

ecoaria o PID do comando1.

O Bash também fornece a armadilha embutida que você pode usar para registrar uma seqüência de comandos a serem executados quando sinais específicos são recebidos. Você pode usar isso para capturar o comando SIGINT e kill1 antes de sair do script principal, por exemplo,

#!/bin/bash

onINT() {
echo "Killing command1 $command1PID too"
kill -INT "$commad1PID"
exit
}

trap "onINT" SIGINT
command1 &
command1PID="$!"
comamnd2
echo Done

Agora, enquanto o comando 2 estiver em execução, pressionar Ctrl C fará com que tanto o comando1 quanto o comando2 sejam enviados SIGINT.

    
por 01.01.2014 / 16:03
4

Versões mais recentes do GNU Parallel farão o que você quiser:

parallel ::: "command 1" "command 2"
echo "done"

Ou se command permanecer o mesmo:

parallel command ::: 1 2
echo done

Assista ao vídeo de introdução para uma introdução rápida: link

Percorra o tutorial (man parallel_tutorial). Você linha de comando com amor por você.

    
por 01.01.2014 / 20:26
2

Ctrl + C envia um sinal SIGINT para o seu processo frontal, que é command2 . command1 é executado em segundo plano, portanto não é afetado pelo fluxo de entrada.

Quando você digita command1 & , o bash deve fornecer o processo 'PID', algo como [1234] . Para matar esse processo, você pode usar kill 1234 . Agora, se você tiver os PIDs de ambos os command1 e command2 (dê uma olhada em ps -ef ), você pode usar kill para finalizar todos eles:

kill pid1 pid2 pid3 ...

Um pequeno truque seria executar os dois comandos em segundo plano, com:

command1 & command2 &

Bash lhe dará os dois PIDs, prontos para serem mortos. Outro truque seria trazer de volta command1 em primeiro plano depois que você matasse command2 :

command1 & command2
# Hit Ctrl+C : command2 terminates.

fg # Bring back command1 to foreground.
# Hit Ctrl+C again, command1 terminates.

Mais informações disponíveis aqui: link

    
por 01.01.2014 / 15:00