シェルスクリプト - 私のプロセスを除く名前ですべてのプロセスを終了する

シェルスクリプト - 私のプロセスを除く名前ですべてのプロセスを終了する

test.shシェルスクリプトが実行中です。

test.shこのスクリプトの冒頭で以前のスクリプトが実行されている場合は、まずそのスクリプトを終了したいと思います。

終了すると、test.sh最新のプロセスもすべて終了します。

私ができる簡単な方法はありますか?

答え1

#!/bin/sh

term_handler () {
    if [ "$ok_to_exit" -eq 1 ]; then
        echo 'exiting'
        exit
    else
        echo 'refusing to exit'
    fi
}

trap term_handler TERM

ok_to_exit=0
pkill -f test.sh
ok_to_exit=1

while true; do
    echo 'working...'
    sleep 2
done

このスクリプト(以下のより簡単なバージョンがあります)は、シグナルが受信されたterm_handlerときにスクリプトを終了するシグナルハンドラをインストールします。TERMもし変数ok_to_exitの値はです1

実行中の操作のいくつかの形式をシミュレートするループがスクリプトの本文にあります。重要なことは、呼び出す前にpkill(これをコマンドで変更できますkillallok_to_exitに設定0してからすぐに設定することです1

一致するすべてのプロセスがシグナルをTERM受信すると、それ自体はシグナルを受け取りますが、シャットダウンを拒否します。他のマッチングプロセス、まったく同じ状態でない場合(同時に複数回スクリプトを起動すると、これが発生する可能性があります。)終了します。

実行するとスクリプトが出力されます。

refusing to exit
working...
working...
working...

スクリプトの他のコピーが起動すると、出力されてexiting終了します。

同じスクリプトのより簡単なバージョン:

#!/bin/sh

trap '' TERM
pkill -f test.sh
trap - TERM

while true; do
    echo 'working...'
    sleep 2
done

これは単に無視するTERM呼び出し中にシグナルを呼び出し、pkill続行する前にデフォルトシグナルハンドラーを復元します。

答え2

シグナルハンドラの使用を避ける良い方法は、自分のプロセスを除くすべてのプロセスにシグナルを送信することです。

for pid in $(pgrep ${0##*/}); do
    if [[ $pid -ne $$ ]]; then
        kill -s TERM $pid
    fi
done

Bashに慣れていない場合は、「/path/to/test.sh」が「test.sh」になるようにデフォルト${0##*/}名(スクリプトが呼び出す名前)が提供されます。$0

答え3

3つ以上のインスタンスを起動する際にいくつかの問題がありますが、pgrep次のように/を使用できます。pkill

#!/bin/sh

while [ "$(pgrep -c -f test.sh)" -gt 1 ]
do
  pkill --oldest -f test.sh
done

# rest of your script

プロセス名自体とより正確に一致するように「test.sh」パラメータを調整してください。

いくつかの例を見てください:

/bin/sh ./test.sh

または

/bin/sh /full/path/to/test.sh

または

/bin/bash ./test.sh

または

sh test.sh

...それで、誤って他のものと一致しなくなります。

答え4

もしみんなあなたの処刑test.sh いつもこのような管理者の確認により、次のことができます。

pid=$(pgrep -o -f "/test.sh( |$)") && [ ${pid} -ne ${$} ] && kill $pid

上記の行は、呼び出し方法に関係なく、現在実行されていない限り、最も古い実行のみを終了します。

ただし、前の実行で欠落しているチェックがないことを絶対に確認したい場合は、上記の行をwhile次のループに入れることができます。

while pid=$(pgrep -o -f "/test.sh( |$)") && [ ${pid} -ne ${$} ] ; do
    kill $pid
done

上で殺すどの前の実行test.sh(呼び出し)

必要に応じて、コマンドの特定のリテラルパラメータも考慮する選択基準が必要になる場合があります。

次のように、確認したいパラメータを二重引用符で囲むことができます。

pgrep注:上記のコードで使用されている部分のみを表示しました。)

pgrep -o -f "/test.sh +arg1 +arg2 *$"

追加+の合計は、*$ これらのパラメータと正確に一致する必要があります。 (この例では、リテラル文字列arg1arg2)。

変数を渡すこともできます。たとえば、理想的なバリエーションは、現在の実行と同じパラメータを使用して実行された以前の実行のみを終了することです。

pgrep -o -f "/test.sh +${*} *$"

これは${*}現在の実行のすべてのパラメータに変換されます。

デフォルトでは、二重引用符内の文字列は有効な正規表現にすることができます。これは、終了したい実行を正確に一致させるのに役立ちます。これは、外部プロセスの終了を防ぐために非常に重要です。

関連情報