Eu tenho um script que inicia 3 janelas do emulador de terminal:
#!/bin/sh
terminator --role='terminator-left' 2>/dev/null &
sleep 0.1
terminator --role='terminator-center' 2>/dev/null &
sleep 0.1
terminator --role='terminator-right' 2>/dev/null &
(Estou usando a opção --role, para poder colocar automaticamente as janelas em monitores diferentes, definidos no meu arquivo de configuração do openbox)
Eu inicio esse script várias vezes, em diferentes desktops virtuais.
Como posso iniciar esses 3 terminais em algum tipo de "grupo de processos", para poder encerrar todos os processos restantes, caso algum dos processos termine?
Importante: não quero encerrar todos os terminais que possam ter sido iniciados em uma instância diferente do meu script (não posso simplesmente usar pkill ou pgrep para encerrar qualquer processo que corresponda a um padrão)
Então, em outras palavras, digamos que eu inicie meu script na área de trabalho virtual 1 e na área de trabalho virtual 2.
Agora tenho 3 janelas de terminal em 2 desktops virtuais diferentes.
Quando saio de um terminal na área de trabalho virtual 1, gostaria que as 2 janelas restantes terminassem automaticamente, mas sem afetar a instância independente de outras 3 janelas em execução na minha área de trabalho virtual 2.
O que descrevo é possível?
Como posso conseguir isso?
Isenção de responsabilidade:
não tive oportunidade de testar minha sugestão no openbox. Eu o validei apenas no kde-plasma.
Minha solução recorre ao
wait
comando interno do shell , conforme documentado no manual dos programadores POSIX . Alguma implementação específica poderia tornar o script mais simples, usando a opção -n.Este script é baseado na ideia de:
Nota 1 (redefinindo o manipulador) : Conforme observado corretamente pelo aviro nos comentários, o manipulador de sinal deve redefinir o tratamento do SIGCHLD para os padrões, pois a eliminação dos processos restantes acionará outro (até 2) SIGCHLD.
Não fazer isso forçaria o shell em algum tipo de situação recursiva (o manipulador tendo que lidar com um sinal que ele mesmo gerou) gerenciado de maneira mais ou menos elegante, dependendo das implementações do shell. (de um aviso inofensivo a alguma profundidade máxima de recursão excedida ou erro equivalente.)
Nota 2 (Manter o tratamento padrão do SIGCHLD até a espera) : Conforme corretamente observado por Martin Vegter nos comentários, a
trap ownkill CHLD
instrução deve ser colocada imediatamente antes da instrução de espera.Colocá-lo como a primeira instrução do script (como eu havia sugerido absurdamente em uma versão anterior) acionaria o manipulador dedicado assim que o primeiro
sleep
processo terminasse.Usando o bash, você pode simplesmente coletar todos os ids do processo e esperar no final para que, quando qualquer processo terminar (bash's
wait -n
), todos os ids sejam eliminados com algum sinal adequado:Como um dos pids já estará morto, redirecionamos o
kill
stderr para null para evitar uma mensagem de erro.Você pode estar disposto a usar uma unidade transitória do systemd, pois é simples de iniciar, controlar e parar. Supondo que seu script de shell seja, digamos,
./myscript
adicione umwait -n
comando ao final dele para que não termine imediatamente, então você pode iniciá-lo com:Este comando retorna imediatamente com a mensagem
Running as unit: mytest1.service
, e você pode ver quais processos estão sendo executados na unidade transitória criada com os comandos usuais:Você pode interromper todos os processos com um comando:
Para executar o mesmo script várias vezes, certifique-se de usar um
--unit=
nome diferente a cada vez. Se todos começarem comtest
, você poderá verificar todos eles ou interrompê-los referindo-se a eles comotest*
.Consulte man systemd-run para várias opções que podem ser úteis, como
--setenv=
,--working-directory=
,--collect
,--wait
. Observe que você também pode passar argumentos para o seu script no final dosystemd-run
comando.