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.
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.