48

GNU バッシュ、バージョン 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

「ps」で独自のプロセスを見つけて終了するたびに、それを解決する方法が間違っていることはわかっています。スクリプトが既に実行されているかどうかを確認するにはどうすればよいfrom that scriptですか?

4

15 に答える 15

61

すでに実行中のプロセスを確認する簡単な方法は、pidofコマンドです。

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

または、スクリプトの実行時に 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"

...

更新: 質問は、スクリプト自体から確認するように変更されました。この場合、常に少なくとも 1 つのabc.sh実行が見られると予想されます。が複数ある場合はabc.sh、プロセスがまだ実行中であることがわかります。pidofプロセスがすでに実行されている場合は、2 つの PID を返すコマンドの使用をお勧めします。grep現在の PID を除外したり、シェルでループしたり、wc複数のプロセスを検出するためにPID をカウントするだけに戻すこともできます。

次に例を示します。

#!/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
于 2013-05-29T07:32:57.970 に答える
32

「pidof」メソッドが必要な場合は、次のトリックを使用します。

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

-o %PPIDパラメーターが、呼び出し元のシェルまたはシェル スクリプトの pid を省略するように指示する場所。詳細については、pidofman ページを参照してください。

于 2015-02-17T14:17:15.270 に答える
11

さまざまな場所で見られる 1 つのトリックを次に示します。

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

を囲む括弧[a](または別の文字を選択)grepは、自分自身を見つけるのを防ぎます。これにより、grep -v grepビットが不要になります。また、同じことを達成するために部品を取り外してgrep -v $$修正しました。awk

于 2013-05-29T21:42:01.223 に答える
10

もし私がここで間違っていたら、誰か私を撃ち落としてください

操作がアトミックであることは理解しているので、ロックディレクトリ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
于 2013-05-29T20:40:34.070 に答える
7

@Austin Phillips からの回答が適切であることがわかりました。私が行う小さな改善の 1 つは、-o (スクリプト自体の pid を無視するため) を追加し、basename を使用してスクリプトに一致させることです (つまり、同じコードを任意のスクリプトに入れることができます)。

if pidof -x "`basename $0`" -o $$ >/dev/null; then
    echo "Process already running"
fi
于 2018-08-15T07:07:05.987 に答える
5

作業ソリューション:

if [[ `pgrep -f $0` != "$$" ]]; then
        echo "Another instance of shell already exist! Exiting"
        exit
fi

編集:最近いくつかのコメントをチェックアウトしたので、デバッグで同じことを試みました。こちらもご説明させていただきます。

説明:

  • $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
    • 修正:#!/bin/bash最初にシバンを使用します。
  2. sudo が機能しない理由は、pgrep が bash を返すのではなく、bash と sudo の両方の PID を返すためです。
    • 修理:
#!/bin/bash
pseudopid="`pgrep -f $0 -l`"
actualpid="$(echo "$pseudopid" | grep -v 'sudo' | awk -F ' ' '{print $1}')"

if [[ `echo $actualpid` != "$$" ]]; then
    echo "Another instance of shell already exist! Exiting"
    exit
fi

while true
do
    echo "Running"
    sleep 100
done
  1. スクリプトが実行されていなくても、スクリプトは終了します。これは、同じファイル名を持つ別のプロセスがあるためです。vim script.sh実行してから実行してみてくださいbash script.sh。vimが同じファイル名で開かれているため失敗します
    • 修正: 一意のファイル名を使用してください。
于 2020-07-01T12:49:37.053 に答える
4

PS コマンドを少し異なる方法で使用して、子プロセスも無視します。

ps -eaf | grep -v grep | grep $PROCESS | grep -v $$
于 2016-01-20T13:37:55.187 に答える
1

これはコンパクトで普遍的です

# exit if another instance of this script is running
for pid in $(pidof -x `basename $0`); do
   [ $pid != $$ ] && { exit 1; }
done
于 2019-09-02T10:44:07.870 に答える