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
(これをコマンドで変更できますkillall
)ok_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 *$"
追加+
の合計は、*$
これらのパラメータと正確に一致する必要があります。 (この例では、リテラル文字列arg1
とarg2
)。
変数を渡すこともできます。たとえば、理想的なバリエーションは、現在の実行と同じパラメータを使用して実行された以前の実行のみを終了することです。
pgrep -o -f "/test.sh +${*} *$"
これは${*}
現在の実行のすべてのパラメータに変換されます。
デフォルトでは、二重引用符内の文字列は有効な正規表現にすることができます。これは、終了したい実行を正確に一致させるのに役立ちます。これは、外部プロセスの終了を防ぐために非常に重要です。