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

时间:2021-06-14 16:24:21

GNU bash, version 1.14.7(1)

GNU bash,版本1.14.7(1)

I have a script is called "abc.sh" I have to check this from abc.sh script only... inside it I have written following statement

我有一个名为“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

I know it's wrong because every time it exits as it found its own process in 'ps' how to solve it? how can I check that script is already running or not from that script only ?

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

11 个解决方案

#1


35  

An easier way to check for a process already executing is the pidof command.

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

if pidof -x "abc.sh" >/dev/null; then
    echo "Process already running"
fi

Alternatively, have your script create a PID file when it executes. It's then a simple exercise of checking for the presence of the PID file to determine if the process is already running.

或者,让脚本在执行时创建一个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"

...

Update: The question has now changed to check from the script itself. In this case, we would expect to always see at least one abc.sh running. If there is more than one abc.sh, then we know that process is still running. I'd still suggest use of the pidof command which would return 2 PIDs if the process was already running. You could use grep to filter out the current PID, loop in the shell or even revert to just counting PIDs with wc to detect multiple processes.

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

Here's an example:

这是一个例子:

#!/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

#2


16  

I you want the "pidof" method, here is the trick:

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

    if pidof -o %PPID -x "abc.sh">/dev/null; then
        echo "Process already running"
    fi

Where the -o %PPID parameter tells to omit the pid of the calling shell or shell script. More info in the pidof man page.

-o%PPID参数指示省略调用shell或shell脚本的pid。更多信息在pidof手册页中。

#3


11  

Here's one trick you'll see in various places:

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

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

The brackets around the [a] (or pick a different letter) prevent grep from finding itself. This makes the grep -v grep bit unnecessary. I also removed the grep -v $$ and fixed the awk part to accomplish the same thing.

[a]周围的括号(或选择不同的字母)可防止grep找到自己。这使得grep -v grep位不必要。我还删除了grep -v $$并修复了awk部分来完成同样的事情。

#4


6  

Someone please shoot me down if I'm wrong here

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

I understand that the mkdir operation is atomic, so you could create a lock directory

我知道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

#5


3  

Use the PS command in a little different way to ignore child process as well:

以稍微不同的方式使用PS命令也可以忽略子进程:

ps -eaf | grep -v grep | grep $PROCESS | grep -v $$

#6


2  

I create a temporary file during execution.

我在执行期间创建了一个临时文件。

This is how I do it:

我是这样做的:

#!/bin/sh
# check if lock file exists
if [ -e /tmp/script.lock ]; then
  echo "script is already running"
else
# create a lock file
  touch /tmp/script.lock
  echo "run script..."
#remove lock file
 rm /tmp/script.lock
fi

#7


1  

Here's how I do it in a bash script:

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

if ps ax | grep $0 | grep -v $$ | grep bash | grep -v grep
then
    echo "The script is already running."
    exit 1
fi

This allows me to use this snippet for any bash script. I needed to grep bash because when using with cron, it creates another process that executes it using /bin/sh.

这允许我将此代码段用于任何bash脚本。我需要grep bash,因为当与cron一起使用时,它会创建另一个使用/ bin / sh执行它的进程。

#8


1  

I have found that using backticks to capture command output into a variable, adversly, yeilds one too many ps aux results, e.g. for a single running instance of abc.sh:

我已经发现使用反引号将命令输出捕获到一个变量中,不幸的是,会产生太多的ps辅助结果,例如:对于abc.sh的单个运行实例:

ps aux | grep -w "abc.sh" | grep -v grep | wc -l

returns "1". However,

返回“1”。然而,

count=`ps aux | grep -w "abc.sh" | grep -v grep | wc -l`
echo $count

returns "2"

返回“2”

Seems like using the backtick construction somehow temporarily creates another process. Could be the reason why the topicstarter could not make this work. Just need to decrement the $count var.

似乎使用反引号构造不知何故暂时创建另一个进程。可能是topicstarter无法使这项工作的原因。只需要递减$ count var。

#9


1  

pidof wasn't working for me so I searched some more and came across pgrep

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

Taken in part from answers above and https://askubuntu.com/a/803106/802276

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

#10


1  

I didn't want to hardcode abc.sh in the check, so I used the following:

我不想在支票上硬编码abc.sh,所以我使用了以下内容:

MY_SCRIPT_NAME=`basename "$0"`
if pidof -o %PPID -x $MY_SCRIPT_NAME > /dev/null; then
    echo "$MY_SCRIPT_NAME already running; exiting"
    exit 1
fi

#11


0  

I find the answer from @Austin Phillips is spot on. One small improvement I'd do is to add -o (to ignore the pid of the script itself) and match for the script with basename (ie same code can be put into any script):

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

if pidof -x "`basename $0`" -o $$ >/dev/null; then
    echo "Process already running"
fi

#1


35  

An easier way to check for a process already executing is the pidof command.

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

if pidof -x "abc.sh" >/dev/null; then
    echo "Process already running"
fi

Alternatively, have your script create a PID file when it executes. It's then a simple exercise of checking for the presence of the PID file to determine if the process is already running.

或者,让脚本在执行时创建一个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"

...

Update: The question has now changed to check from the script itself. In this case, we would expect to always see at least one abc.sh running. If there is more than one abc.sh, then we know that process is still running. I'd still suggest use of the pidof command which would return 2 PIDs if the process was already running. You could use grep to filter out the current PID, loop in the shell or even revert to just counting PIDs with wc to detect multiple processes.

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

Here's an example:

这是一个例子:

#!/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

#2


16  

I you want the "pidof" method, here is the trick:

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

    if pidof -o %PPID -x "abc.sh">/dev/null; then
        echo "Process already running"
    fi

Where the -o %PPID parameter tells to omit the pid of the calling shell or shell script. More info in the pidof man page.

-o%PPID参数指示省略调用shell或shell脚本的pid。更多信息在pidof手册页中。

#3


11  

Here's one trick you'll see in various places:

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

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

The brackets around the [a] (or pick a different letter) prevent grep from finding itself. This makes the grep -v grep bit unnecessary. I also removed the grep -v $$ and fixed the awk part to accomplish the same thing.

[a]周围的括号(或选择不同的字母)可防止grep找到自己。这使得grep -v grep位不必要。我还删除了grep -v $$并修复了awk部分来完成同样的事情。

#4


6  

Someone please shoot me down if I'm wrong here

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

I understand that the mkdir operation is atomic, so you could create a lock directory

我知道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

#5


3  

Use the PS command in a little different way to ignore child process as well:

以稍微不同的方式使用PS命令也可以忽略子进程:

ps -eaf | grep -v grep | grep $PROCESS | grep -v $$

#6


2  

I create a temporary file during execution.

我在执行期间创建了一个临时文件。

This is how I do it:

我是这样做的:

#!/bin/sh
# check if lock file exists
if [ -e /tmp/script.lock ]; then
  echo "script is already running"
else
# create a lock file
  touch /tmp/script.lock
  echo "run script..."
#remove lock file
 rm /tmp/script.lock
fi

#7


1  

Here's how I do it in a bash script:

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

if ps ax | grep $0 | grep -v $$ | grep bash | grep -v grep
then
    echo "The script is already running."
    exit 1
fi

This allows me to use this snippet for any bash script. I needed to grep bash because when using with cron, it creates another process that executes it using /bin/sh.

这允许我将此代码段用于任何bash脚本。我需要grep bash,因为当与cron一起使用时,它会创建另一个使用/ bin / sh执行它的进程。

#8


1  

I have found that using backticks to capture command output into a variable, adversly, yeilds one too many ps aux results, e.g. for a single running instance of abc.sh:

我已经发现使用反引号将命令输出捕获到一个变量中,不幸的是,会产生太多的ps辅助结果,例如:对于abc.sh的单个运行实例:

ps aux | grep -w "abc.sh" | grep -v grep | wc -l

returns "1". However,

返回“1”。然而,

count=`ps aux | grep -w "abc.sh" | grep -v grep | wc -l`
echo $count

returns "2"

返回“2”

Seems like using the backtick construction somehow temporarily creates another process. Could be the reason why the topicstarter could not make this work. Just need to decrement the $count var.

似乎使用反引号构造不知何故暂时创建另一个进程。可能是topicstarter无法使这项工作的原因。只需要递减$ count var。

#9


1  

pidof wasn't working for me so I searched some more and came across pgrep

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

Taken in part from answers above and https://askubuntu.com/a/803106/802276

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

#10


1  

I didn't want to hardcode abc.sh in the check, so I used the following:

我不想在支票上硬编码abc.sh,所以我使用了以下内容:

MY_SCRIPT_NAME=`basename "$0"`
if pidof -o %PPID -x $MY_SCRIPT_NAME > /dev/null; then
    echo "$MY_SCRIPT_NAME already running; exiting"
    exit 1
fi

#11


0  

I find the answer from @Austin Phillips is spot on. One small improvement I'd do is to add -o (to ignore the pid of the script itself) and match for the script with basename (ie same code can be put into any script):

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

if pidof -x "`basename $0`" -o $$ >/dev/null; then
    echo "Process already running"
fi