检测工具是否已在执行,但仅适用于当前用户

检测工具是否已在执行,但仅适用于当前用户

到目前为止我用

pidof -o %PPID -x "my-tool"

检测 my-tool 最终运行实例的 pid。

这是 my-tool 文件的简短版本,一个可执行 bash 脚本

#!/bin/bash 

if pidof -o %PPID -x "my-tool"; then
   echo "Already running"
   exit 1
fi

 ... if not running go on 

但现在我需要允许每个用户一个实例,每台机器多个实例,因此我们可以同时运行 100 个 my-tool,但每个用户只能运行 1 个。

请注意,我需要一个测试来创建类似单例的东西。如果该工具启动时有另一个实例正在运行,它将自行关闭。

简而言之:我需要一个 bash 脚本能够检测自身是否已为当前用户运行,在这种情况下它必须退出。

如何 ?

答案1

改用pgrep

pgrep -cxu $USER -f my-tool

使用的选项是:

   -c, --count
          Suppress  normal  output; instead print a count of matching pro‐
          cesses.  When count does not match anything, e.g. returns  zero,
          the command will return non-zero value.
   -x, --exact
          Only match processes whose names (or command line if -f is spec‐
          ified) exactly match the pattern.
   -u, --euid euid,...
          Only match processes whose effective user ID is listed.   Either
          the numerical or symbolical value may be used.

如果要在检查是否已在运行的 bash 脚本中使用它,可以使用$0。这会扩展到当前脚本的路径(例如/home/username/bin/foo.sh),但我们只需要foo.sh。为此,我们可以/使用 bash 的字符串操作工具: ${0##*/}。这意味着我们可以做类似的事情:

## If there are more than 1 instances of the current script run
## by this user
if [[ $(pgrep -cxu "$USER" "${0##*/}") -gt 1 ]];
then
        echo "Script already running, exiting."
        exit
fi

您可能还想考虑为此使用锁文件:

## If the lock file exists
if [ -e /tmp/$USER.foo.lock ]; then
    ## Check if the PID in the lockfile is a running instance
    ## of foo.sh to guard against crashed scripts
    if ps $(cat /tmp/$USER.foo.lock) | grep foo.sh >/dev/null; then
        echo "Script foo.sh is already running, exiting"
        exit
    else
        echo "Lockfile contains a stale PID, continuing"
        rm /tmp/$USER.foo.lock 
    fi
fi
## Create the lockfile by printing the script's PID into it
echo $$ > /tmp/$USER.foo.lock

## Rest of the script here

## At the end, delete the lockfile
rm /tmp/$USER.foo.lock

答案2

您可以使用pgrep它来查找某个进程是否由特定用户执行,如果该用户尚未运行该进程,则启动该进程:

#!/bin/bash
if pgrep -u "$USER" my-tool &>/dev/null; then
    echo 'You already have my-tool running'
else
    /path/to/my_tool
fi

环境变量$USER将被扩展到当前登录的用户,即运行脚本的用户。由于我们只关心 是否正在my-tool运行,因此直接使用 with 构造的退出状态if就足够了。

使用此脚本作为启动的包装器my-tool并让用户仅使用它或将其重命名为my-tool并将原始脚本重命名my-tool为其他名称(并更改脚本内部的名称)。

答案3

用这个代码片段尝试一下:

#!/bin/bash
MyProcessName=$(ps -p $$ -o args=)
Mypid=$$
AllPids=$(pgrep -fu "$(whoami)" "$MyProcessName")
AllPids=$(tr "\n" ' ' <<<"$AllPids")
Pids=$(sed "s/$Mypid//" <<<"$AllPids")
echo "$$: Instances including itself: $AllPids"
echo "$$: Instances different from itself: $Pids"

不要写,pgrep|tr因为这会分叉到同名的 shell,这一点很重要。

答案4

将您想要运行的命令包装在一个 flock 中,以确保一次只运行一个副本。使用存储在用户主目录树中的 lock_file,以便每个用户都有自己的锁定文件。例如:

lockfile = "~/lockfile"
(
 if flock -n 200; then
    command
 else
    echo "Could not get lock $lock_file
 fi
) 200>$lock_file

‘command’ 可以是任何 bash 命令或脚本。

man flock给出使用示例

相关内容