如何检查我的shell脚本的另一个实例是否正在运行

Jat*_*rya 34 bash shell concurrency

GNU bash,版本1.14.7(1)

我有一个脚本被称为" abc.sh"我必须从abc.sh脚本中检查这个...在其中我写了以下语句

status=`ps -efww | grep -w "abc.sh" | grep -v grep | grep -v $$ | awk '{ print $2 }'`
if [ ! -z "$status" ]; then
        echo "[`date`] : abc.sh : Process is already running"
        exit 1;
fi
Run Code Online (Sandbox Code Playgroud)

我知道这是错的,因为每次它退出,因为它在'ps'中找到了自己的进程如何解决它?如何检查脚本是否已经运行from that script

Aus*_*ips 48

检查已经执行的进程的更简单方法是pidof命令.

if pidof -x "abc.sh" >/dev/null; then
    echo "Process already running"
fi
Run Code Online (Sandbox Code Playgroud)

或者,让脚本在执行时创建一个PID文件.然后,这是一个检查PID文件是否存在的简单练习,以确定该进程是否已在运行.

#!/bin/bash
# abc.sh

mypidfile=/var/run/abc.sh.pid

# Could add check for existence of mypidfile here if interlock is
# needed in the shell script itself.

# Ensure PID file is removed on program exit.
trap "rm -f -- '$mypidfile'" EXIT

# Create a file with current PID to indicate that process is running.
echo $$ > "$mypidfile"

...
Run Code Online (Sandbox Code Playgroud)

更新: 现在问题已更改为从脚本本身进行检查.在这种情况下,我们希望总能看到至少一次abc.sh运行.如果有多个abc.sh,那么我们知道该进程仍在运行.我仍然建议使用该pidof命令,如果进程已经运行,它将返回2个PID.您可以使用grep过滤掉当前PID,在shell中循环,甚至还可以恢复为仅计数PID wc来检测多个进程.

这是一个例子:

#!/bin/bash

for pid in $(pidof -x abc.sh); do
    if [ $pid != $$ ]; then
        echo "[$(date)] : abc.sh : Process is already running with PID $pid"
        exit 1
    fi
done
Run Code Online (Sandbox Code Playgroud)

  • @frederickjh 或者 `$(basename $0)`: `for pid in $(pidof -x $(basename $0)); 做` (2认同)

Aba*_*Aba 24

我想要"pidof"方法,这就是诀窍:

    if pidof -o %PPID -x "abc.sh">/dev/null; then
        echo "Process already running"
    fi
Run Code Online (Sandbox Code Playgroud)

-o %PPID参数告诉省略调用shell或shell脚本的PID.pidof手册页中的更多信息.

  • 对于 /system/bin/sh,(Android 默认 SHELL)我必须使用“-o $$”修改它,所以我的代码看起来像这样 ```if pidof -o $$ -x "$0" > /dev/无效的; 然后回显“进程已在运行”;fi``` 不知道为什么“-o %PPID”对我来说无法排除我的脚本。 (3认同)

Mac*_*dav 13

工作解决方案:

if [[ `pgrep -f $0` != "$$" ]]; then
        echo "Another instance of shell already exist! Exiting"
        exit
fi
Run Code Online (Sandbox Code Playgroud)

编辑:我最近查看了一些评论,所以我尝试尝试进行一些调试。我也会解释一下。

解释:

  • $0 给出正在运行的脚本的文件名。
  • $$ 给出正在运行的脚本的 PID。
  • pgrep 按名称搜索进程并返回 PID。
  • pgrep -f $0 按文件名搜索,$0 是当前 bash 脚本文件名并返回其 PID。

因此,pgrep 检查您的脚本 PID ($0) 是否等于当前运行的脚本 ($$)。如果是,则脚本正常运行。如果不是,则意味着有另一个具有相同文件名的 PID 正在运行,因此它会退出。pgrep -f $0我使用而不是的原因pgrep bash是你可以运行多个 bash 实例,从而返回多个 PID。根据文件名,它仅返回单个 PID。

例外情况:

  1. 不要使用bash script.shnot,./script.sh因为除非你有 shebang,否则它不起作用。
    • 修复:#!/bin/bash一开始就使用shebang。
  2. sudo 不起作用的原因是它返回 pgrep 返回 bash 和 sudo 的 PID,而不是返回 bash 的 。
    • 使固定:
if [[ `pgrep -f $0` != "$$" ]]; then
        echo "Another instance of shell already exist! Exiting"
        exit
fi
Run Code Online (Sandbox Code Playgroud)
  1. 即使脚本未运行,脚本也会退出。这是因为另一个进程具有相同的文件名。尝试执行vim script.sh然后运行bash script.sh,它会失败,因为 vim 用相同的文件名打开
    • 修复:使用唯一的文件名。


twa*_*erg 10

这是你在各个地方看到的一个技巧:

status=`ps -efww | grep -w "[a]bc.sh" | awk -vpid=$$ '$2 != pid { print $2 }'`
if [ ! -z "$status" ]; then
    echo "[`date`] : abc.sh : Process is already running"
    exit 1;
fi
Run Code Online (Sandbox Code Playgroud)

围绕[a](或选择不同的字母)的括号可防止grep发现自己.这使得这个grep -v grep位不必要.我也删除grep -v $$并修复了awk部分以完成同样的事情.


gle*_*man 8

如果我在这里错了,有人请把我击倒

我知道该mkdir操作是原子操作,因此您可以创建一个锁定目录

#!/bin/sh
lockdir=/tmp/AXgqg0lsoeykp9L9NZjIuaqvu7ANILL4foeqzpJcTs3YkwtiJ0
mkdir $lockdir  || {
    echo "lock directory exists. exiting"
    exit 1
}
# take pains to remove lock directory when script terminates
trap "rmdir $lockdir" EXIT INT KILL TERM

# rest of script here
Run Code Online (Sandbox Code Playgroud)

  • 这有效,但它使一个人处于不知道进程是否实际运行的位置,如果它(可能)崩溃? (2认同)

小智 6

我发现@Austin Phillips 的答案恰到好处。我要做的一个小改进是添加 -o(忽略脚本本身的 pid)并使用 basename 匹配脚本(即相同的代码可以放入任何脚本中):

if pidof -x "`basename $0`" -o $$ >/dev/null; then
    echo "Process already running"
fi
Run Code Online (Sandbox Code Playgroud)


Car*_*ruz 5

这是我在bash脚本中执行的操作:

if ps ax | grep $0 | grep -v $$ | grep bash | grep -v grep
then
    echo "The script is already running."
    exit 1
fi
Run Code Online (Sandbox Code Playgroud)

这使我可以将此片段用于任何bash脚本。我需要grep bash,因为与cron一起使用时,它创建了另一个使用/ bin / sh执行它的进程。

  • 这是我发现的唯一可在Mac OS X上运行的解决方案。 (2认同)

小智 5

pidof不适合我,所以我又搜索了一些,发现了pgrep

for pid in $(pgrep -f my_script.sh); do
    if [ $pid != $$ ]; then
        echo "[$(date)] : my_script.sh : Process is already running with PID $pid"
        exit 1
    else
      echo "Running with PID $pid"
    fi  
done
Run Code Online (Sandbox Code Playgroud)

部分摘自上面的答案和https://askubuntu.com/a/803106/802276