尽管在前台捕获信号,仍停止带有后台进程的子 shell 接收SIGINT

ohtdti5x  于 2023-03-09  发布在  Shell
关注(0)|答案(1)|浏览(132)

假设我有一个在前台运行的函数,这个函数捕获SIGINT并忽略EOF(用于防止Control + C和Control + D),这个函数创建一个在后台运行命令的子shell。
我会认为SIGINT会被主函数捕获。然而,在运行主函数时使用Control + C仍然会导致子shell接收SIGINT并在预期之前被杀死。
我还尝试在子shell中添加SIGINT陷阱和忽略EOF陷阱,但似乎也不起作用。
下面是一个相对简单的示例,使用mpv命令概括了该问题:

function play_video_until_yes {
    trap '' 2
    set -o ignoreeof
    
    videourl="$1"
    read -r mpv_pid < <(mpv --loop "$videourl" --no-video &>/dev/null & echo $!)
    
    while true; do
        read -rp "Input y for yes: " answer
        if [[ "$answer" = "y" ]]; then
            break
        fi
        printf "\nIncorrect. Try again.\n"
    done
    
    kill "$mpv_pid" >/dev/null
    
    trap 2
    set +o ignoreeof
}

你可以用任何YouTube视频的命令行参数(例如play_video_until_yes "https://www.youtube.com/watch?v=usNsCeOV4GM")运行这个函数,然后在主进程请求用户输入时按Control + C,这会导致子shell退出,可能是由于SIGINT。

vcudknz3

vcudknz31#

我对此做了相当多的研究,并能够找到一个答案。它起作用,但不太理想。
我不得不通过Homebrew在Mac上安装一个名为util-linux的独立软件包来获取setsid命令,然后,我能够使用该命令在一个独立的进程组中运行mpv命令,以防止SIGINT被转发到该进程组。
所以,这是我的解决方案看起来像这样:

function play_video_until_yes {
    trap '' 2
    set -o ignoreeof

    videourl="$1"
    read -r mpv_pid < <( /opt/homebrew/opt/util-linux/bin/setsid mpv --loop "$videourl" --no-video &>/dev/null & echo $!)

    while true; do
        read -rp "Input y for yes: " answer
        if [[ "$answer" = "y" ]]; then
            break
        fi
        printf "\nIncorrect. Try again.\n"
    done

    kill "$mpv_pid" >/dev/null

    trap 2
    set +o ignoreeof
}

我仍然更喜欢使用macOS上已经存在的命令的解决方案,但这个解决方案目前站稳了脚跟。

相关问题