
Se me ocurrió una configuración que imagino que hará eso, excepto que no 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"
En la primera ejecución, parece que todo está bien, puedo finalizar el proceso touch kill_flag
; de lo contrario, espera hasta que myprog finalice normalmente. Pero luego me di cuenta de que siempre obtengo el -1 en recuperación. myprog devuelve 0 según lo confirmado por una ejecución normal. Una investigación adicional indicó que la echo $?
parte " " se ejecutó inmediatamente después de iniciar el script, no después de que finalice el comando de espera. Me pregunto qué está pasando aquí. Soy bastante nuevo en esto.
Respuesta1
wait
sólo puede funcionar en hijos del proceso de shell actual. La subcapa que interpreta el código interno <(...)
no puede esperar a un proceso hermano.
La espera tendría que realizarse mediante el mismo proceso de shell que inició el pid. Con zsh
en lugar de bash
(aquí suponiendo que no se esté ejecutando ningún otro trabajo en segundo plano):
cmd & pid=$!
while (($#jobstates)) {
[[ -e killfile ]] && kill $pid
sleep 3
}
wait $pid; echo $?
Respuesta2
Descubrí una versión viable:
#!/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"
Lo único molesto es que cuando mato myprog con un semáforo, aparecerá un error ya que la sustitución del proceso está muerta, pero se puede atrapar fácilmente.