调用退出并不像预期的那样工作

时间:2016-05-27 12:07:02

标签: bash

我需要在它们之间运行后台和管道数据中的几个子进程。当脚本退出时,我想杀死剩下的任何一个,所以我添加了

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)。 AI脚本很简单:

#!/bin/sh
while true; do
    echo END_TURN
done

我的脚本中没有任何wait调用。我做错了什么?

有趣的是:当我在jobs -p之后立即致电run_ai2 &时,我会列出3个pid。另一方面,当我从cleanup函数调用此命令时 - 输出为空。

此外,为什么sleep $turndelay进程终止了?它不是一个儿童调用过程。

2 个答案:

答案 0 :(得分:1)

我猜你正在通过子进程启动一些子进程。这样做:在另一个窗口中执行ps -ft pts/1或任何你的tty。验证

同时将pkill更改为kill $(jobs -p)并查看是否有效。

答案 1 :(得分:1)

陷阱脚本退出时会触发EXIT陷阱。您的顶级脚本不会退出此处。

trap不会被子shell继承,你的run_*函数正在运行(从后台运行)所以它永远不会在子shell&#39时触发退出。

你想要的最有可能是你手动做的(虽然听起来有点不正确)。

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终止时发出主脚本信号来使其更明确来代替。)