関数でpidofを実行する

関数でpidofを実行する

私のスクリプトがすでに実行されているかどうかを検出したいので、次のようにします。これ:

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 && othercommandcheckIfRunningcheckIfRunning

そして、欠陥は処理されず、トリガーerrexitされます。故障によるものerrexitではなく、故障によるものです。pidofcheckIfRunning

ここに以下を書く必要があります。

checkIfRunning() {
  if pidof -o %PPID -x -- "$0" >/dev/null; then
    echo >&2 'Already running!'
    exit 1
  fi
}

構成済みの終了状態はif、セクションで実行された最後のコマンドの終了状態、または実行されたコマンドがない場合は条件セクションの終了状態です。thenelse0

通常、ifand-or リストの代替構造は次のとおりです。間違った。全体的なシャットダウン状態の問題に加えて、スクリプトがecho失敗した場合pidof && echo && exit 1、スクリプトは終了しません。

errexit私はこれを避ける必要があり、関数や最も単純なスクリプト以外のものを使用する場合は、適切なエラー処理を実行する必要があると思います。

バラよりset -euo pipefailBash 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成功状態で終了するからです。したがって、これcheckIfRunningset +e関連性がなく、不要で、orset -eに置き換えることができます。truereturn 0

おすすめ記事