英文:
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 '' 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
}
One can run this function with a command-line argument of any YouTube video (e.g. play_video_until_yes "https://www.youtube.com/watch?v=usNsCeOV4GM"
) 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 '' 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上已经存在的命令的解决方案,但目前这个解决方案还是可以的。
英文:
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 '' 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
}
I would still prefer a solution that uses commands already present on macOS, but this solution stands its ground for now.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论