我需要在后台运行几个子进程,并在它们之间建立管道数据。当脚本退出时,我想杀死它们中的任何一个,所以我添加了
trap cleanup EXIT
cleanup()
{
echo "Cleaning up!"
pkill -TERM -P $$
}因为我需要在其中一个进程报告错误时做出反应,所以我创建了包装函数。任何以fd结尾的东西都是以前打开的文件描述符,连接到FIFO管道。
run_gui()
{
"$GAME_BIN" $args <&$gui_infd >&$gui_outfd # redirecting IO to some file descriptors
if [[ $? == 0 ]]; then
echo exiting ok
exit $OK_EXITCODE
else
exit $ERROR_EXITCODE
fi
}run_ai1(), run_ai2的功能类似。
run_ai1()
{
"$ai1" <&$ai1_infd >&$ai1_outfd
if [[ $? == 0 || $? == 1 || $? == 2 ]]; then
exit $OK_EXITCODE
else
exit $ERROR_EXITCODE
fi
}
run_ai2()
{
"$ai2" <&$ai2_infd >&$ai2_outfd
if [[ $? == 0 || $? == 1 || $? == 2 ]]; then
exit $OK_EXITCODE
else
exit $ERROR_EXITCODE
fi
}然后运行函数并执行所需的管道操作。
printinit 1 >&$ai1_infd
printinit 2 >&$ai2_infd
run_gui &
run_ai1 &
run_ai2 &
while true; do
echo "Started the loop"
while true; do
read -u $ai1_outfd line || echo "Nothing read"
echo $line
if [[ $line ]]; then
echo "$line" >&$gui_infd
echo "$line" >&$ai2_infd
if [[ "$line" == "END_TURN" ]]; then
break
fi
fi
done
sleep $turndelay
while true; do
read -u $ai2_outfd line || echo "nothing read"
echo $line
if [[ $line ]]; then
echo "$line" >&$gui_infd
echo "$line" >&$ai1_infd
if [[ "$line" == "END_TURN" ]]; then
break
fi
fi
done
sleep $turndelay
done当$GAME_BIN退出(即GUI被关闭按钮关闭)时,我可以在stdout上看到exiting ok消息,但是根本没有调用cleanup函数。当我在调用cleanup之前添加对exit $OK_EXITCODE的手动调用时,尽管进程被终止了:
./game.sh: line 309: 9193 Terminated run_gui
./game.sh: line 309: 9194 Terminated run_ai1
./game.sh: line 309: 9195 Terminated run_ai2
./game.sh: line 309: 9203 Terminated sleep $turndelay循环无论如何都会运行,并且脚本不会像它应该退出的那样退出(exit $OK_EXITCODE)。人工智能脚本很简单:
#!/bin/sh
while true; do
echo END_TURN
done我的脚本中任何地方都没有wait调用。我做错了什么?
有趣的是:当我在jobs -p之后立即调用run_ai2 &时,我会列出3个pids。另一方面,当我从cleanup函数调用这个命令时,输出是空的。
此外,为什么sleep $turndelay进程会终止?这不是一个被调用的子进程。
发布于 2016-05-31 16:04:58
当捕获脚本退出时,EXIT陷阱会触发。你的图层剧本不在这里。
trap不是由运行run_*函数的子shell继承的(从后台运行),因此它不会在子shell退出时触发。
你想要的很可能是你手动做的事情(虽然听起来有点不对)。
您希望在cleanup退出时从run_gui调用$GAME函数。就像这样。
run_gui() {
"$GAME_BIN" $args <&$gui_infd >&$gui_outfd # redirecting IO to some file descriptors
ret=$?
cleanup
exit $ret
}然后,您只需要确保cleanup获得正确的$$值(在bash中,它甚至在子shell中也是如此,因为子shell中的$$是父进程ID,但是您可能希望在主脚本中为信号设置一个处理程序,并在run_gui终止时给主脚本发送信令)。
发布于 2016-05-27 13:13:01
我猜你得到了一个子进程启动的子进程。这样做:在另一个窗口中做一个ps -ft pts/1或者你的tty是什么。核实一下。
还可以将pkill更改为kill $(jobs -p),并查看这是否有效。
https://stackoverflow.com/questions/37483161
复制相似问题