我编写了一个 shell 脚本run_script.sh
,其中包括创建空文件的步骤run_script.lck
。每次 cronjob 调用 shell 脚本时,它都会检查run_script.lck
.如果锁存在,则表明该程序run_script.sh
已经在运行并且尚未完成。该run_script.lck
文件将在程序结束时被删除。
麻烦的是在 shell 脚本崩溃时和退出之前删除锁定文件。
我写了这样一行:
trap "rm -f run_script.lck" EXIT
但它会在不希望的情况下删除锁定文件,如下所示:
我run_script.sh
在 shell A 中执行,它正在运行,锁定文件已创建。然后我在shell B中再次执行它,它说脚本已经在运行,脚本将被中止。但是,由于陷阱收到了一个 EXIT 信号,其中包括来自 shell B 的信号(该信号正在退出已中止的脚本),因此它会删除锁定文件。 shell A 中的脚本仍在运行,但锁已被删除,任何人都可以run_script.sh
在已有一个脚本正在运行时再次调用另一个脚本。
知道如何解决这个问题吗?
答案1
检查锁是否存在前设置陷阱。
答案2
为了说明 Ignacio 的答案(使用以下协议:首先检查锁定文件是否存在,然后安装陷阱),您可以像这样解决问题:
$ cat test2.sh
if [ -f run_script.lck ]; then
echo Script $0 already running
exit 1
fi
trap "rm -f run_script.lck" EXIT
# rest of the script ...
答案3
方法是设置错误陷阱并sh
在出现错误时中止脚本 ( set -e
)。例如
$ cat test.sh
set -e
trap "echo foo" ERR
if [ $# == 1 ]; then
exit 0
fi
false
$ bash test.sh
foo
$ bash test.sh 1
$
(其中$#
是参数的数量)
在您的脚本中,您只需确保在脚本成功运行时执行 trap 命令(即没有发生崩溃,例如在正常程序流程结束时)。
set -e
表示每次退出状态不相等0
都会结束脚本的执行。与此类似,set -u
每次(可能是意外)使用未定义的变量都会结束执行。
因此,将此想法转移到原始用例中,解决方案可能如下所示:
$ cat test.sh
set -e
trap "rm -f run_script.lck" ERR
if [ -f run_script.lck ]; then
echo Script $0 is already running
exit 1
fi
#
# do all the work ...
#
# no error until now
rm -f run_script.lck