ツールがすでに実行中であるかどうかを検出しますが、現在のユーザーに対してのみ


8

今まで使った

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

最終的に実行中のmy-toolのインスタンスのpidを検出します。

これは、実行可能なbashスクリプトであるmy-toolファイルの短縮バージョンです。

#!/bin/bash 

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

 ... if not running go on 

しかし、ユーザーごとに1つのインスタンスとマシンごとに複数のインスタンスを許可する必要があるので、同時に100のmy-toolを実行できますが、ユーザーごとに1つしかありません。

シングルトンのようなものを作成するにはテストが必要です。ツールが開始され、別のインスタンスが実行されている場合、ツールは自動的に終了します。

つまり、bashスクリプトが現在のユーザーに対して既に実行されているかどうかを検出でき、この場合は終了する必要があります。

方法 ?


あなたは使用すべきではありませんpidof、より良いツールがありますpgrep
猫、

回答:


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。これは現在のスクリプト(eg /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そのようなプロセスが実際に存在するかどうかをテストするロジックを含めることができます。
モンティハーダー2016

@MontyHarder確かに、非常に良い提案です。回答を編集しました。ありがとうございます。
terdon 2016

@terdonはモバイルに問題があり、そのコメントをすぐに削除しました。の$(< pidfile)代わりに私は意味しました$(cat pidfile)
sdkks

7

pgrepプロセスが特定のユーザーによって実行されている場合はfo find を使用し、ユーザーによってまだ実行されていない場合はプロセスを開始できます。

#!/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が実行されているかどうかにのみ関心があるため、if構成で直接終了ステータスを使用するだけで十分です。

このスクリプトを開始用のラッパーとして使用しmy-tool、ユーザーにこれのみを使用させるかmy-tool、名前を変更して元の名前をmy-tool別の名前に変更します(スクリプト内の名前も変更します)。


ラッパー、長い履歴を作成できません...現在のプロセスのPIDを除外するにはどうすればよいですか?
realtebo

@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同じ名前のシェルにforkするため、記述しないことが重要です。


2

実行するコマンドを群れでラップして、一度に1つのコピーのみが実行されるようにします。各ユーザーが独自のロックファイルを持つように、ユーザーのホームディレクトリツリー内に格納されている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
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.