如何避免在 Bash 脚本中终止错误的进程?

如何避免在 Bash 脚本中终止错误的进程?

我正在编写一个 bash 脚本,它会生成几个子进程,并由一个cron作业每小时运行一次。它实际上是rsync向远程服务器运行命令以及相关ssh连接。

如果 rsync 命令或脚本耗时过长,我想终止它及其子进程,但首先要给它一个宽限期。该脚本每小时运行一次,但接下来的两次尝试将看到该脚本的上一个实例正在运行,并在尝试开始传输之前退出。第三次后续尝试将终止仍在运行的原始实例,然后再开始新的传输。

我决定通过写入 PID 文件来控制这一点,第一个实例将其 PID 写入文件,接下来的两次尝试在退出之前将其 PID 写入文件。第三次尝试会杀死第一个,然后用新的 PID 覆盖 PID 文件。任何成功完成都会擦除 PID 文件。为了杀死所有子项,我决定使用原始脚本实例的 PGID,我通过以下方式获得:

previous_pid=$(head -n1 "$pid_file")
previous_groupid=$(ps -hp "$previous_pid" -o pgid:1)

然后用以下方法杀死它:

kill -- -"$previous_pid"

我担心的是,可能存在这样的情况:原始脚本在没有清理 PID 文件的情况下就死掉了,而且 PID 被重用,同时也重用了 PGID,所以我最终会终止一个完全不相关的进程。我该如何避免这种情况?

答案1

让脚本自行终止。例如,在脚本开头添加如下内容:

kill_myself () {
    while sleep 1
    do
        if [[ -f /tmp/kill-myself ]]
        then
            rm /tmp/kill-myself
            kill -- -$1
        fi
    done
}

kill_myself $$ &

现在,时机成熟了:

touch /tmp/kill-myself

您可以自定义它,这样脚本的每个实例都有自己的终止文件,您可以将其记录在某处。然后您将使用该文件终止该脚本的特定实例。


另一种方法:您可能可以使用pgrep/pkill进行更精细的匹配。它们可以从 pid 文件中读取,与命令名称和参数进行匹配等。

类似下面的操作只会终止与您的脚本同名的进程(假设您以script-name或 的形式调用它/path/to/script-name):

pkill -g "$previous_groupid" script-name

如果您这样做,这将不起作用bash script-name。或者只是终止命令rsync,这可能会让您的脚本在那之后退出:

pkill -g "$previous_groupid" rsync

相关内容