shell脚本中的错误处理

shell脚本中的错误处理

我编写了一个 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

相关内容