
Eu criei uma configuração que imagino que fará isso, exceto que não funciona:
#!/bin/bash
echo "Launching a background process that may take hours to finish.."
myprog &
pid=$!
retval=
##At this time pid should hold the process id of myprog
echo "pid=${pid}"
{
##check if the process is still running
psl=$(ps -f -p ${pid} | grep -E "\bmyprog\b")
killit=
while [[ ! -z ${psl} ]]
do
##if a file named "kill_flag" is detected, kill the process
if [[ -e "kill_flag" ]]
then
killit=YES
break
fi
#check every 3 seconds
sleep 3
psl=$(ps -f -p ${pid} | grep -E "\bmyprog\b")
done
##killit not set, normal exit, read from fd5
if [[ -z ${killit} ]]
then
read <&5 retval
else
##kill here, the wait will return and the sub process ends
kill ${pid}
fi
} 5< <( wait ${pid} > /dev/null 2>&1; echo $? )
echo "retval=$retval"
Na primeira execução parece tudo bem, posso encerrar o processo touch kill_flag
, caso contrário ele espera até que o myprog termine normalmente. Mas então percebi que sempre recebo -1 em retval. myprog retorna 0 conforme confirmado por uma execução normal. Investigações adicionais indicaram que a echo $?
parte " " foi executada imediatamente após o lançamento do script, e não após a saída do comando wait. Estou me perguntando o que está acontecendo aqui. Eu sou muito novo no bash.
Responder1
wait
só pode funcionar em filhos do processo shell atual. O subshell que interpreta o código interno <(...)
não pode esperar por um processo irmão.
A espera teria que ser feita pelo mesmo processo shell que iniciou o pid. Com zsh
em vez de bash
(aqui, assumindo que não há outro trabalho em segundo plano em execução):
cmd & pid=$!
while (($#jobstates)) {
[[ -e killfile ]] && kill $pid
sleep 3
}
wait $pid; echo $?
Responder2
Descobri uma versão viável:
#!/bin/bash
export retval=
##At this time pid should hold the process id of myprog
{
##This is the subshell that launched and monitoring myprog
subsh=$!
##Since myprog is probably the only child process of this subsh, it should be pretty safe
pid=$(ps -f --ppid ${subsh} | grep -E "\bmyprog\b" | gawk '{print $2}' )
##check if the process is still running
psl=$(ps -f -p ${pid} | grep -E "\bmyprog\b")
killit=
while [[ ! -z ${psl} ]]
do
##if a file named "kill_flag" is detected, kill the process
if [[ -e "kill_flag" ]]
then
killit=YES
break
fi
#check every 3 seconds
sleep 3
psl=$(ps -f -p ${pid} | grep -E "\bmyprog\b")
done
##killit not set, normal exit, read from fd5
if [[ -z ${killit} ]]
then
read <&5 retval
else
##kill here, the wait will return and the sub process ends
kill ${pid}
fi
} 5< <( myprog >>logfile 2>&1; echo $? )
echo "retval=$retval"
A única coisa irritante é que quando eu mato myprog com um semáforo, um erro surgirá porque a substituição do processo está morta, mas pode ser facilmente capturada.