
私のスクリプトがすでに実行されているかどうかを検出したいので、次のようにします。これ:
pidof -o %PPID -x "$0" >/dev/null && echo 'already running!' && exit 1
これはうまくいきます。しかし、私はそれを関数にしたいと思います。
#!bin/bash
set -eu
set -o pipefail
checkIfRunning() {
pidof -o %PPID -x "$0" >/dev/null && echo 'already running!' && exit 1
}
#...
checkIfRunning
これはうまくいきません。実行中のスクリプトインスタンスが1つしかない場合でも、常に終了します。
pidof
サブシェルで実行すると、サブシェルとスクリプトを検出して結果を解釈すると思います。しかし、ここでサブシェルがどのように生成されるのかわかりませんか?
この問題の原因は何であり、どのように解決できますか?
答え1
コードで処理されていないコマンドが失敗するとset -e
(略語でset -o errexit
)、シェルは終了します。
pidof
一致するプロセスが見つからない場合、失敗した終了ステータスが返されますが、ユーザーは失敗を処理しました。pidof
次のように使用そして - またはリストだから実際に失敗しますいいえトリガーerrexit
。
でも、使ったからそして - またはリストゼロ以外の終了状態で終了するコンストラクタをif
使用する必要がある場合、そのand-or-listは関数で最後に実行されるため、関数自体も失敗した終了状態を返します。pidof && othercommand
checkIfRunning
checkIfRunning
そして、欠陥は処理されず、トリガーerrexit
されます。故障によるものerrexit
ではなく、故障によるものです。pidof
checkIfRunning
ここに以下を書く必要があります。
checkIfRunning() {
if pidof -o %PPID -x -- "$0" >/dev/null; then
echo >&2 'Already running!'
exit 1
fi
}
構成済みの終了状態はif
、セクションで実行された最後のコマンドの終了状態、または実行されたコマンドがない場合は条件セクションの終了状態です。then
else
0
通常、if
and-or リストの代替構造は次のとおりです。間違った。全体的なシャットダウン状態の問題に加えて、スクリプトがecho
失敗した場合pidof && echo && exit 1
、スクリプトは終了しません。
errexit
私はこれを避ける必要があり、関数や最も単純なスクリプト以外のものを使用する場合は、適切なエラー処理を実行する必要があると思います。
バラよりset -euo pipefail
Bash Wikiの対応するセクション(の略語set -o errexit -o nounset -o pipefail
)またはこのよくある質問。
~についてあなたの(現在削除された)回答この問題を解決しようとします。
checkIfRunning() { set +e # <--- pidof -o %PPID -x $0 >/dev/null \ && echo "running!" && exit 1 set -e # <--- }
動作する唯一の理由は、set -e
成功状態で終了するからです。したがって、これcheckIfRunning
もset +e
関連性がなく、不要で、orset -e
に置き換えることができます。true
return 0