停止子Shell中的后台进程接收SIGINT信号,尽管在前台捕获信号。

huangapple go评论71阅读模式
英文:

Stop subshell with background process from receiving SIGINT despite trapping signals in the foreground

问题

我有一个在前台运行的函数。这个函数捕获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信号。

英文:

Let us say I have a function that is run in the foreground. This function traps SIGINT and ignores EOF (for preventing Control + C and Control + D). This function creates a subshell that runs a command in the background.

I would think that SIGINT would be caught by the main function. However, using Control + C while running the main function does still result in the subshell receiving SIGINT and being killed before what is expected.

I have also attempted to add the traps for SIGINT and ignoring EOF in the subshell itself, but that did not seem to work either.

Here is a relatively-minimal example that encapsulates the issue, using the mpv command:

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

One can run this function with a command-line argument of any YouTube video (e.g. play_video_until_yes &quot;https://www.youtube.com/watch?v=usNsCeOV4GM&quot;) and press Control + C while the main process is asking for user input. This causes the subshell to quit, presumably due to the SIGINT.

答案1

得分: 0

我对此进行了相当多的研究,找到了一个答案。它可以工作,但不是最理想的。

我不得不在我的Mac上通过Homebrew安装一个名为util-linux的单独软件包,以获取setsid命令。然后,我能够使用该命令在一个单独的进程组中运行mpv命令,以防止将SIGINT转发给它。

因此,以下是在此之后我的解决方案的样子:

function play_video_until_yes {
    trap &#39;&#39; 2
    set -o ignoreeof

    videourl=&quot;"$1"&quot;
    read -r mpv_pid &lt; &lt;( /opt/homebrew/opt/util-linux/bin/setsid mpv --loop &quot;"$videourl"&quot; --no-video &amp;&gt;/dev/null &amp; echo $!)

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

    kill &quot;"$mpv_pid"&quot; &gt;/dev/null

    trap 2
    set +o ignoreeof
}

我仍然希望找到一个使用macOS上已经存在的命令的解决方案,但目前这个解决方案还是可以的。

英文:

I did a fair amount of research on this and was able to find one answer. It works, but it is less than ideal.

I had to install a separate package called util-linux via Homebrew on my Mac to get the setsid command. Then, I was able to use that command to run the mpv command in a separate process group to prevent SIGINT from being forwarded to it.

So, here is what my solution looked like after that:

function play_video_until_yes {
    trap &#39;&#39; 2
    set -o ignoreeof

    videourl=&quot;$1&quot;
    read -r mpv_pid &lt; &lt;( /opt/homebrew/opt/util-linux/bin/setsid mpv --loop &quot;$videourl&quot; --no-video &amp;&gt;/dev/null &amp; echo $!)

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

    kill &quot;$mpv_pid&quot; &gt;/dev/null

    trap 2
    set +o ignoreeof
}

I would still prefer a solution that uses commands already present on macOS, but this solution stands its ground for now.

huangapple
  • 本文由 发表于 2023年2月27日 19:16:37
  • 转载请务必保留本文链接:https://go.coder-hub.com/75579764.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定