我正在编写一个旨在用作守护进程的Bash脚本.如果我的脚本的用户没有向脚本传递–sync选项,我希望脚本使用该选项将其自身重新运行为后台任务.这是我的代码(最后一部分是从this SO post被盗):
#!/usr/bin/env bash
args=("$@") # capture them here so we can use them if --sync's not passed
async=true
while [ $# -gt 0 ]
do
case "$1" in
--sync)
async=false
;;
# other options
esac
shift
done
# if --sync isn't passed, rerun the script as a background task
$async && exec nohup "${BASH_SOURCE[0]}" --sync "${args[@]}" 0 /dev/null &
出于某种原因,它似乎没有起作用.当我执行bash -x myscript(这有助于调试脚本)时,即使$async为true,它似乎仍然继续运行,我认为这不会发生,因为exec通常会停止执行.
同样,如果我从终端运行此命令:
exec nohup true 0 /dev/null &
尽管使用了exec,它也无法退出shell.为什么会这样,我该怎么做才能解决这个问题? (加分点:如果不创建子shell,有没有办法做到这一点?)
谢谢.
解决方法:
&正在应用于exec命令本身,所以exec foo&分叉一个新的异步子shell(或其等价物,见下文).子shell立即用foo替换自己.如果您希望父(也就是您的脚本)也终止,您需要使用exit命令显式地执行此操作.
这位高管可能不会在这里给你买任何东西. Bash非常聪明,实际上并没有为简单的后台命令启动子shell.所以它应该足够:
if $async; then
nohup "${BASH_SOURCE[0]}" --sync "${args[@]}" 0 /dev/null &
exit 0
fi
我不知道没有子shell的方法.但是当你编写shell脚本时,你会得到子shell.就个人而言,我只是使用一个简单的变量并使用if [[$async]]等测试它;而不是执行true或false,但由于这些也是bash内置的,它非常相同.在其他炮弹中,它们可以在子炮弹中运行.
现在我想到了,因为你无论如何都在重新处理异步执行中的所有选项,你可能只是在case语句中fork和exit,所以你根本不需要第二次检查:
case "$1" in
--sync)
nohup "${BASH_SOURCE[0]}" --sync "${args[@]}" 0 /dev/null &
exit 0
;;
标签:bash,shell,unix,linux,sh
来源: https://codeday.me/bug/20190623/1270145.html