我想构建一个执行命令的bash脚本,同时执行其他操作,如果脚本被杀死,可能会杀死命令.比如说,执行大文件的cp并同时打印自复制开始以来经过的时间,但是如果脚本被杀死它也会杀死副本.我并不想用rsync的,原因有二:1)是缓慢的,2)我想学习如何做到这一点,它可能是有用的.我试过这个:
until cp SOURCE DEST
do
#evaluates time, stuff, commands, file dimensions, not important now
#and echoes something
done
Run Code Online (Sandbox Code Playgroud)
但是它没有执行do - done块,因为它正在等待副本结束.你能建议一下吗?
Joh*_*ica 36
until与...相反while.当另一个命令运行时,它与做事情无关.为此,您需要在后台运行您的任务&.
cp SOURCE DEST &
pid=$!
# If this script is killed, kill the `cp'.
trap "kill $pid 2> /dev/null" EXIT
# While copy is running...
while kill -0 $pid 2> /dev/null; do
# Do stuff
...
sleep 1
done
# Disable the trap on a normal exit.
trap - EXIT
Run Code Online (Sandbox Code Playgroud)
kill -0检查进程是否正在运行.请注意,它实际上并不表示进程并将其终止,正如名称所暗示的那样.至少不是信号0.
Ada*_*iss 11
解决问题涉及三个步骤:
在后台执行命令,因此当脚本执行其他操作时它将继续运行.您可以通过执行以下命令来执行此操作&.有关详细信息,请参阅Bash参考手册中有关作业控制的部分.
跟踪该命令的状态,以便您知道它是否仍在运行.您可以使用特殊变量执行此操作,该变量$!设置为您在后台运行的最后一个命令的PID(进程标识符),如果没有启动后台命令,则为空.Linux /proc/$PID为每个正在运行的进程创建一个目录,并在进程退出时删除它,因此您可以检查该目录是否存在,以确定后台命令是否仍在运行.您可以/proc从Linux Documentation Project的文件系统层次结构页面或Advanced Bash-Scripting Guide中了解更多您想知道的内容.
如果您的脚本被终止,请终止后台命令.您可以使用trap命令执行此操作,该命令是bash内置命令.
把碎片放在一起:
# Look for the 4 common signals that indicate this script was killed.
# If the background command was started, kill it, too.
trap '[ -z $! ] || kill $!' SIGHUP SIGINT SIGQUIT SIGTERM
cp $SOURCE $DEST & # Copy the file in the background.
# The /proc directory exists while the command runs.
while [ -e /proc/$! ]; do
echo -n "." # Do something while the background command runs.
sleep 1 # Optional: slow the loop so we don't use up all the dots.
done
Run Code Online (Sandbox Code Playgroud)
请注意,我们检查/proc目录以查明后台命令是否仍在运行,因为kill -0如果在该进程不再存在时调用它将生成错误.
更新解释使用trap:
语法是trap [arg] [sigspec …],其中sigspec …是要捕获的信号列表,并且arg是在引发任何这些信号时执行的命令.在这种情况下,命令是一个列表:
'[ -z $! ] || kill $!'
Run Code Online (Sandbox Code Playgroud)
这是一种常见的bash习语,它利用了||处理方式.cmd1 || cmd2如果cmd1OR cmd2成功,表单的表达式将评估为成功.但是bash很聪明:如果cmd1成功,bash知道完整的表达式也必须成功,所以它不需要去评估cmd2.另一方面,如果cmd1失败,则结果cmd2确定表达式的整体结果.因此,一个重要的特征 ||是它cmd2只有在cmd1失败时才会执行.这意味着它是(无效)序列的快捷方式:
if cmd1; then
# do nothing
else
cmd2
fi
Run Code Online (Sandbox Code Playgroud)
考虑到这一点,我们可以看到
trap '[ -z $! ] || kill $!' SIGHUP SIGINT SIGQUIT SIGTERM
Run Code Online (Sandbox Code Playgroud)
将测试是否$!为空(这意味着后台任务从未执行过).如果失败,这意味着任务已执行,则会终止任务.