Todos os exemplos são escritos em bash, mas (com mudanças mínimas) funcionarão em ksh. O Csh também possui um recurso para gerenciar processos em segundo plano, portanto, uma abordagem semelhante também pode ser usada.
CONTROLE DE TRABALHO
Este é o nome da seção do man bash onde os detalhes são descritos, caso você goste de ler man. Usamos os seguintes recursos simples:
command & - executa um comando nos
trabalhos em segundo plano - imprime uma lista de comandos em segundo plano
Um exemplo simples que não executa nenhuma ação útil. Os números são lidos a partir do arquivo test.txt e 3 processos são iniciados em paralelo, que ficam suspensos pelo número de segundos correspondente. A cada três segundos, o número de processos em execução é verificado e, se houver menos de três, um novo é iniciado. O lançamento do processo em segundo plano foi movido para uma função separada mytask, mas você pode iniciá-lo diretamente em um loop.
test.sh
#!/bin/bash
NJOBS=3 ; export NJOBS
function mytask () {
echo sleeping for $1
sleep $1
}
for i in $( cat test.txt )
do
while [ $(jobs | wc -l ) -ge $NJOBS ]
do
sleep 3
done
echo executing task for $i
mytask $i &
done
echo waiting for $( jobs | wc -l ) jobs to complete
wait
Dados de entrada:
test.txt
60
50
30
21
12
13
50
30
21
12
13
Preste atenção à espera após o loop, o comando espera que os processos em execução em segundo plano terminem. Sem ele, o script será encerrado imediatamente após o término do ciclo e todos os processos em segundo plano serão interrompidos. Talvez essa espera seja mencionada no famoso meme "oh, espere !!!".
Encerrando processos em segundo plano
Se você interromper o script com Ctrl-C, ele será encerrado com todos os processos em segundo plano. todos os processos em execução no terminal recebem sinais do teclado (por exemplo, SIGINT). Se o script for eliminado de outro terminal com o comando kill, os processos em segundo plano permanecerão em execução até o término e você precisa se lembrar disso.
Cabeçalho de spoiler
user@somehost ~/tmp2 $ ps -ef | grep -E «test|sleep»
user 1363 775 0 12:31 pts/5 00:00:00 ./test.sh
user 1368 1363 0 12:31 pts/5 00:00:00 ./test.sh
user 1370 1368 0 12:31 pts/5 00:00:00 /usr/bin/coreutils --coreutils-prog-shebang=sleep /usr/bin/sleep 60
user 1373 1363 0 12:31 pts/5 00:00:00 ./test.sh
user 1375 1373 0 12:31 pts/5 00:00:00 /usr/bin/coreutils --coreutils-prog-shebang=sleep /usr/bin/sleep 50
user 1378 1363 0 12:31 pts/5 00:00:00 ./test.sh
user 1382 1378 0 12:31 pts/5 00:00:00 /usr/bin/coreutils --coreutils-prog-shebang=sleep /usr/bin/sleep 30
user 1387 1363 0 12:31 pts/5 00:00:00 /usr/bin/coreutils --coreutils-prog-shebang=sleep /usr/bin/sleep 3
user 1389 556 0 12:31 pts/2 00:00:00 grep --colour=auto -E test|sleep
user@somehost ~/tmp2 $ kill 1363
user@somehost ~/tmp2 $ ps -ef | grep -E «test|sleep»
user 1368 1 0 12:31 pts/5 00:00:00 ./test.sh
user 1370 1368 0 12:31 pts/5 00:00:00 /usr/bin/coreutils --coreutils-prog-shebang=sleep /usr/bin/sleep 60
user 1373 1 0 12:31 pts/5 00:00:00 ./test.sh
user 1375 1373 0 12:31 pts/5 00:00:00 /usr/bin/coreutils --coreutils-prog-shebang=sleep /usr/bin/sleep 50
user 1378 1 0 12:31 pts/5 00:00:00 ./test.sh
user 1382 1378 0 12:31 pts/5 00:00:00 /usr/bin/coreutils --coreutils-prog-shebang=sleep /usr/bin/sleep 30
user 1399 556 0 12:32 pts/2 00:00:00 grep --colour=auto -E test|sleep
user 1363 775 0 12:31 pts/5 00:00:00 ./test.sh
user 1368 1363 0 12:31 pts/5 00:00:00 ./test.sh
user 1370 1368 0 12:31 pts/5 00:00:00 /usr/bin/coreutils --coreutils-prog-shebang=sleep /usr/bin/sleep 60
user 1373 1363 0 12:31 pts/5 00:00:00 ./test.sh
user 1375 1373 0 12:31 pts/5 00:00:00 /usr/bin/coreutils --coreutils-prog-shebang=sleep /usr/bin/sleep 50
user 1378 1363 0 12:31 pts/5 00:00:00 ./test.sh
user 1382 1378 0 12:31 pts/5 00:00:00 /usr/bin/coreutils --coreutils-prog-shebang=sleep /usr/bin/sleep 30
user 1387 1363 0 12:31 pts/5 00:00:00 /usr/bin/coreutils --coreutils-prog-shebang=sleep /usr/bin/sleep 3
user 1389 556 0 12:31 pts/2 00:00:00 grep --colour=auto -E test|sleep
user@somehost ~/tmp2 $ kill 1363
user@somehost ~/tmp2 $ ps -ef | grep -E «test|sleep»
user 1368 1 0 12:31 pts/5 00:00:00 ./test.sh
user 1370 1368 0 12:31 pts/5 00:00:00 /usr/bin/coreutils --coreutils-prog-shebang=sleep /usr/bin/sleep 60
user 1373 1 0 12:31 pts/5 00:00:00 ./test.sh
user 1375 1373 0 12:31 pts/5 00:00:00 /usr/bin/coreutils --coreutils-prog-shebang=sleep /usr/bin/sleep 50
user 1378 1 0 12:31 pts/5 00:00:00 ./test.sh
user 1382 1378 0 12:31 pts/5 00:00:00 /usr/bin/coreutils --coreutils-prog-shebang=sleep /usr/bin/sleep 30
user 1399 556 0 12:32 pts/2 00:00:00 grep --colour=auto -E test|sleep
Essa situação pode ser tratada interceptando os sinais necessários, para os quais adicionamos um manipulador no início do script:
armadilha
function pids_recursive() {
cpids=`pgrep -P $1|xargs`
echo $cpids
for cpid in $cpids;
do
pids_recursive $cpid
done
}
function kill_me () {
kill -9 $( pids_recursive $$ | xargs )
exit 1
}
#
#trap 'echo trap SIGINT; kill_me ' SIGINT
trap 'echo trap SIGTERM; kill_me' SIGTERM
kill -L exibe uma lista de sinais existentes, se necessário, você pode adicionar manipuladores para os necessários.