
Ich habe eine Einstellung gefunden, die das meiner Meinung nach bewerkstelligen wird, allerdings funktioniert sie nicht:
#!/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"
Beim ersten Durchlauf scheint alles in Ordnung zu sein, ich kann den Prozess mit beenden touch kill_flag
, andernfalls wartet er, bis myprog normal fertig ist. Aber dann ist mir aufgefallen, dass ich bei retval immer -1 bekomme. myprog gibt 0 zurück, was bei einem normalen Durchlauf bestätigt wird. Weitere Untersuchungen haben ergeben, dass der echo $?
Teil „ “ unmittelbar nach dem Start des Skripts ausgeführt wurde, nicht nach Beendigung des Wartebefehls. Ich frage mich, was hier los ist. Ich bin ziemlich neu bei Bash.
Antwort1
wait
kann nur an untergeordneten Prozessen des aktuellen Shell-Prozesses arbeiten. Die Subshell, die den Code darin interpretiert, <(...)
kann nicht auf einen Schwesterprozess warten.
Die Wartezeit müsste vom selben Shell-Prozess übernommen werden, der die PID gestartet hat. Anstelle zsh
von bash
(hier wird vorausgesetzt, dass kein anderer Hintergrundjob läuft):
cmd & pid=$!
while (($#jobstates)) {
[[ -e killfile ]] && kill $pid
sleep 3
}
wait $pid; echo $?
Antwort2
Habe eine praktikable Version gefunden:
#!/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"
Das einzig Ärgerliche ist, dass, wenn ich myprog mit einem Semaphor beende, ein Fehler auftritt, da die Prozessersetzung tot ist, aber dieser kann leicht abgefangen werden.