Maneira confiável de obter código de saída de um processo em segundo plano enquanto monitora e mata quando necessário

1

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, que eu posso matar o processo por touch kill_flag , caso contrário, aguarde até que o myprog termine normalmente. Mas então eu percebi que sempre recebo o -1 em retval. myprog retorna 0 como confirmado por uma execução normal. Investigações posteriores indicaram que a parte " echo $? " foi executada imediatamente após o script ser iniciado, não depois que o comando wait foi encerrado. Eu estou querendo saber o que está acontecendo aqui. Eu sou muito novo para bater.

    
por Shine 21.11.2017 / 17:01

2 respostas

0

wait só pode funcionar nos filhos do processo de shell atual. O subshell que interpreta o código dentro de <(...) não pode esperar por um processo irmão.

A espera teria que ser feita pelo mesmo processo de shell que iniciou o pid. Com zsh em vez de bash (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 $?
    
por 21.11.2017 / 17:43
0

Descobriu 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 chata é que quando eu mato o myprog com um semáforo, um erro irá aumentar quando a substituição do processo estiver morta, mas ele pode ficar preso facilmente.

    
por 21.11.2017 / 18:54

Tags