Executar vários comandos e matá-los como um em bash

44

Eu quero executar vários comandos (processos) em um único shell. Todos eles têm saída contínua própria e não param. Executá-los no fundo quebra Ctrl - C . Eu gostaria de executá-los como um único processo (subshell, talvez?) Para poder parar todos eles com Ctrl - C .

Para ser específico, quero executar testes de unidade com mocha (modo de observação), executar o servidor e executar algum pré-processamento de arquivo (modo de observação) e ver a saída de cada um em uma janela de terminal. Basicamente eu quero evitar usar algum corredor de tarefas.

Eu posso perceber isso executando processos em segundo plano ( & ), mas depois tenho que colocá-los em primeiro plano para interrompê-los. Eu gostaria de ter um processo para envolvê-los e quando eu parar o processo, ele parará seus 'filhos'.

    
por user1876909 20.05.2015 / 07:34

5 respostas

58

Para executar comandos simultaneamente, você pode usar o separador de comando & .

~$ command1 & command2 & command3

Isso iniciará command1 e, em seguida, será executado em segundo plano. O mesmo com command2 . Então começa command3 normalmente.

A saída de todos os comandos será truncada, mas se isso não for um problema para você, essa seria a solução.

Se você quiser dar uma olhada separada na saída mais tarde, poderá canalizar a saída de cada comando para tee , o que permite especificar um arquivo para espelhar a saída.

~$ command1 | tee 1.log & command2 | tee 2.log & command3 | tee 3.log

A saída provavelmente será muito confusa. Para combater isso, você poderia dar à saída de cada comando um prefixo usando sed .

~$ echo 'Output of command 1' | sed -e 's/^/[Command1] /' 
[Command1] Output of command 1

Então, se juntarmos tudo isso, conseguiremos:

~$ command1 | tee 1.log | sed -e 's/^/[Command1] /' & command2 | tee 2.log | sed -e 's/^/[Command2] /' & command3 | tee 3.log | sed -e 's/^/[Command3] /'
[Command1] Starting command1
[Command2] Starting command2
[Command1] Finished
[Command3] Starting command3

Esta é uma versão altamente idealizada do que você provavelmente verá. Mas é o melhor que posso pensar agora.

Se você quiser interromper todos eles de uma só vez, use a compilação em trap .

~$ trap 'kill %1; kill %2' SIGINT
~$ command1 & command2 & command3

Isso executará command1 e command2 no fundo e command3 no primeiro plano, o que permite que você o mate com Ctrl + C .

Quando você mata o último processo com Ctrl + C , os comandos kill %1; kill %2 são executados, porque nós conectamos sua execução com a recepção de um INLINE SIGnal, a coisa enviado pressionando Ctrl + C .

Eles matam respectivamente o primeiro e o segundo processo em segundo plano (seu command1 e command2 ). Não se esqueça de remover a armadilha, depois de terminar seus comandos usando trap - SIGINT .

Complete o monstro de um comando:

~$ trap 'kill %1; kill %2' SIGINT
~$ command1 | tee 1.log | sed -e 's/^/[Command1] /' & command2 | tee 2.log | sed -e 's/^/[Command2] /' & command3 | tee 3.log | sed -e 's/^/[Command3] /'

Você poderia, é claro, dar uma olhada na tela . Ele permite que você divida seu console em quantos consoles separados desejar. Então você pode monitorar todos os comandos separadamente, mas ao mesmo tempo.

    
por 20.05.2015 / 17:11
17

Você pode facilmente matar um monte de processos de uma só vez se você organizá-los (e somente eles) no mesmo grupo de processos .

O Linux fornece o utilitário setsid para executar um programa em um novo grupo de processos (em uma nova sessão , mesmo, mas não nos importamos com isso). (Isso é factível, mas mais complicado sem setsid .)

O ID do grupo de processos (PGID) de um grupo de processos é o ID do processo pai original no grupo. Para eliminar todos os processos em um grupo de processos, passe o negativo do PGID para a chamada ou comando do sistema kill . O PGID permanece válido mesmo se o processo original com este PID morrer (embora possa ser um pouco confuso).

setsid sh -c 'command1 & command2 & command3' &
pgid=$!
echo "Background tasks are running in process group $pgid, kill with kill -TERM -$pgid"

Se você executar os processos em segundo plano a partir de um shell não interativo , todos eles permanecerão no grupo de processos do shell. É apenas em shells interativos que os processos em segundo plano são executados em seu próprio grupo de processos. Portanto, se você separar os comandos de um shell não interativo que permanece em primeiro plano, Ctrl + C irá matar todos eles. Use o wait builtin para fazer o shell esperar que todos os comandos saiam.

sh -c 'command1 & command2 & command3 & wait'
# Press Ctrl+C to kill them all
    
por 21.05.2015 / 03:09
10

Surpreende-me que isto ainda não esteja aqui, mas a minha forma preferida de o fazer é utilizar subcasas com comandos em segundo plano. Uso:

(command1 & command2 & command3)

A saída é visível de ambos, todos os comandos bash e conveniências ainda estão disponíveis, e um único Ctrl-c mata todos eles. Eu costumo usar isso para iniciar um servidor de arquivos do cliente de depuração ao vivo e um servidor backend ao mesmo tempo, para que eu possa matá-los facilmente quando quiser.

A maneira como isso funciona é que command1 e command2 estão sendo executados no segundo plano de uma nova instância de subshell e command3 está no primeiro plano dessa instância, e a subshell é a primeira a receber o sinal de kill um pressionamento de tecla Ctrl-c . É muito parecido com a execução de um script bash com relação a quem possui qual processo e quando os programas em segundo plano são mortos.

    
por 14.03.2018 / 17:15
0

Você pode usar o ponto-e-vírgula ; ou && da seguinte forma:

cmd1; cmd2   # Runs both the commands, even if the first one exits with a non-zero status.

cmd1 && cmd2 # Only runs the second command if the first one was successful.
    
por 20.05.2015 / 07:54
-1

Você pode usar um pipe . Isto irá iniciar os comandos em ambas as extremidades do tubo ao mesmo tempo. Você deve conseguir parar todos os comandos com o CTRL-C também.

1st command | 2nd command | 3rd command

Se você quiser executar os comandos um após o outro, você pode usar o método @ serenesat.

    
por 20.05.2015 / 09:42