防止SIGINT关闭bash脚本中的子进程 [英] Prevent SIGINT from closing child process in bash script
问题描述
我正在编写一个bash脚本,其中编写了一个处理程序来照顾用户何时按下Control + C(通过使用trap interruptHandler SIGINT
),但SIGINT既发送到bash脚本又发送到子进程,即当前正在运行,正在关闭子进程.如何防止这种情况发生?
I am writing a bash script in which I wrote a handler to take care of when the user pressed Control+C, (by using trap interruptHandler SIGINT
) but the SIGINT gets sent to both the bash script and the child process that is currently running, closing the child process. How can I prevent this from happening?
这是脚本,不要过多批评我的技能.
edit: here's the script, don't critique my skills too much..
#!/bin/bash
trap "interruptHandler" SIGINT
inInterrupt=false;
quit=false;
if [ -z ${cachedir+x} ]; then cachedir=~/.cache/zlima12.encoding; fi
cachedir=$(realpath ${cachedir});
if [ ! -e ${cachedir} ]; then mkdir ${cachedir}; fi
if [ ! -e ${cachedir}/out ]; then mkdir ${cachedir}/out; fi
cleanCache ()
{
rm ${cachedir}/*.mkv;
rm ${cachedir}/out/*.mkv;
}
interruptHandler ()
{
if [ ${inInterrupt} != true ]; then
printf "BASHPID: ${BASHPID}";
inInterrupt=true;
ffmpegPID=$(pgrep -P ${BASHPID});
kill -s SIGTSTP ${ffmpegPID};
printf "\nWould you like to quit now(1) or allow the current file to be encoded(2)? ";
read response;
if [ ${response} = "1" ]; then kill ${ffmpegPID}; cleanCache;
elif [ ${response} = "2" ]; then quit=true; kill -s SIGCONT ${ffmpegPID};
else printf "I'm not sure what you said... continuing execution.\n"; kill -s SIGCONT ${ffmpegPID};
fi
inInterrupt=false;
fi
}
for param in "$@"; do
dir=$(realpath ${param});
if [ ! -e ${dir} ]; then
printf "Directory ${dir} doesn't seem to exist... Exiting...\n"
exit 1;
elif [ -e ${dir}/new ]; then
printf "${dir}/new already exists! Proceed? (y/n) ";
read response;
if [ ${response} != y ]; then exit 1; fi
else
mkdir ${dir}/new;
fi
for file in ${dir}/*.mkv; do
filename="$(basename ${file})";
cp $file ${cachedir}/${filename};
ffmpeg -vsync passthrough -i ${cachedir}/${filename} -c:v libx265 -c:a copy -f matroska ${cachedir}/out/${filename};
rm ${cachedir}/${filename};
mv ${cachedir}/out/${filename} ${dir}/new/${filename};
if [ ${quit} = true ]; then exit 0; fi
done
done
(这是一个脚本,用于在您好奇的情况下将matroska(mkv)文件编码为H.265)
(This is a script to encode matroska (mkv) files to H.265 in case you're curious)
推荐答案
在此处执行了一个简单的测试,并提供了预期的结果:
Performed a simple test here and it delivers the expected result:
int.sh
内容:
#!/bin/bash
trap '' SIGINT
tail -f /var/log/syslog >& /dev/null
测试:
$ ./int.sh
^C^C
# ... SIGINT ignored (CTRL+C) ...
# ... Will send SIGTSTP with CTRL+Z ...
^Z
[1]+ Stopped ./int.sh
$ kill %1
$
[1]+ Terminated ./int.sh
$
编辑(回答问题):
您可能希望捕获并忽略其他命令(例如脚本中的(trap '' SIGINT && command)
)的SIGINT
,因此可以防止在调用interruptHandler
之前从当前命令捕获信号.
You probably want to trap and ignore SIGINT
for every other command, such as (trap '' SIGINT && command)
in your script, so you can prevent the signal being caught from the current command before interruptHandler
is invoked.
一个简单的例子:
#!/bin/bash
function intHandler() {
echo "If SIGINT was caught, this will be printed AFTER sleep exits."
}
trap intHandler SIGINT
sleep 5 # Sleep will exit as soon as SIGINT is caught
输出:
$ time ./int.sh
^C
# ... Right here, only 0.6 seconds have elapsed before the below message being printed ...
If SIGINT was caught, this will be printed AFTER sleep exits.
real 0m0.634s
user 0m0.004s
sys 0m0.000s
请注意,由于捕获了SIGINT
,它只持续了0.6秒.
Note that it only lasted for 0.6 seconds due to SIGINT
being caught.
但是当您忽略sleep
的SIGINT时:
But when you ignore SIGINT for sleep
:
function intHandler() {
echo "If SIGINT was caught, this will be printed AFTER sleep exits."
}
trap intHandler SIGINT
(trap '' SIGINT && sleep 5)
输出为:
$ time ./int.sh
^C
# ... Right here, 5 seconds have elapsed without any message ...
If SIGINT was caught, this will be printed AFTER sleep exits.
real 0m5.007s
user 0m0.000s
sys 0m0.000s
请注意,尽管SIGINT
已被脚本传递并捕获,但intHandler
仅在当前sleep
退出时返回,并且还请注意,当前sleep
并未捕获SIGINT
从父级(持续了整整5秒钟)开始,直到它运行所在的子shell(( ... )
)忽略了SIGINT
.
Note that despite the SIGINT
was delivered and caught by the script, the intHandler
will only return when the current sleep
exits, and also note that the current sleep
didn't caught the SIGINT
from the parent (it lasted for the full 5 seconds) as the subshell where it's running on (the ( ... )
) is ignoring SIGINT
.
这篇关于防止SIGINT关闭bash脚本中的子进程的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!