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


8

到现在为止

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

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

这是我的工具文件(可执行的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脚本可以检测自身是否已经为当前用户运行,并且在这种情况下必须退出。

如何 ?


您不应该使用pidof,还有更好的工具在说谎pgrep

Answers:


12

使用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


1
而不是 touch /tmp/$USER.foo.lock我将使用进程的PID,echo $$ >/tmp/$USER.foo.lock然后可以包含逻辑以测试这样的进程是否确实存在。
Monty Harder

@MontyHarder确实是非常好的建议。答案已编辑,谢谢。

@terdon在手机方面遇到问题,在下一秒钟删除了该评论。我的意思$(< pidfile)不是$(cat pidfile)
sdkks

7

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

#!/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正在运行感兴趣,因此,仅将exit状态直接与if结构一起使用就足够了。

使用此脚本作为启动程序的包装my-tool,使用户仅使用此脚本,或者将其重命名为my-tool,并将原始my-tool名称重命名为其他名称(并在脚本内部也更改名称)。


我不能做一个包装器,历史悠久,...如何排除当前的过程PID?
realtebo '16

@realtebo ummm ..排除PID的含义?
heemayl

2

尝试使用以下代码段:

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


2

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

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

“命令”可以是任何bash命令或脚本。

man flock 给出用法示例


真的,我一点都不了解flock命令
realtebo,
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.