しかし、私はps
人々がそれらを使用しているのを見続けているので、いくつかのさまざまな壊れた半実行可能なアプローチとそれらが持つ多くの警告について説明したいと思います。
この答えは、「シェルでロックを使用して処理しない理由」に対する答えです。ps
grep
壊れたアプローチ#1
まず、別の回答で示されているアプローチで、機能しない(および機能しない可能性があり、明らかにテストされていないという事実にもかかわらず、いくつかの賛成票がある):
running_proc=$(ps -C bash -o pid=,cmd= | grep my_script);
if [[ "$running_proc" != "$$ bash my_script" ]]; do
echo Already locked
exit 6
fi
構文エラーと壊れたps
引数を修正して、以下を取得しましょう。
running_proc=$(ps -C bash -o pid,cmd | grep "$0");
echo "$running_proc"
if [[ "$running_proc" != "$$ bash $0" ]]; then
echo Already locked
exit 6
fi
このスクリプトは、実行方法に関係なく、常に 6で終了します。
で実行すると./myscript
、ps
出力はになりますが12345 -bash
、これは必要な文字列12345 bash ./myscript
と一致しないため、失敗します。
で実行するとbash myscript
、さらに面白くなります。bashプロセスはパイプラインを実行するために分岐し、子シェルはps
andを実行しgrep
ます。元のシェルと子シェルの両方がps
出力に表示されます。次のようなものです。
25793 bash myscript
25795 bash myscript
これは期待される出力$$ bash $0
ではないため、スクリプトは終了します。
壊れたアプローチ#2
壊れたアプローチ#1を書いたユーザーに公平を期して、これを最初に試したとき、私は自分自身に似たようなことをしました。
if otherpids="$(pgrep -f "$0" | grep -vFx "$$")" ; then
echo >&2 "There are other copies of the script running; exiting."
ps >&2 -fq "${otherpids//$'\n'/ }" # -q takes about a tenth the time as -p
exit 1
fi
これはほとんど機能します。しかし、パイプを実行するために分岐するという事実はこれをスローします。したがって、これも常に終了します。
信頼性の低いアプローチ#3
pids_this_script="$(pgrep -f "$0")"
if not_this_process="$(echo "$pids_this_script" | grep -vFx "$$")"; then
echo >&2 "There are other copies of this script running; exiting."
ps -fq "${not_this_process//$'\n'/ }"
exit 1
fi
このバージョンでは、最初にコマンドライン引数に現在のスクリプトを含むすべてのPIDを取得し、次にそのpidlistを個別にフィルタリングして現在のスクリプトのPIDを省略することにより、アプローチ#2のパイプラインフォークの問題を回避します。
これは機能する可能性があります。他のプロセスにに一致するコマンドラインがない場合$0
、スクリプトは常に同じ方法で呼び出されます(たとえば、相対パスと絶対パスで呼び出された場合、後者のインスタンスは前者に気付かないでしょう) )。
信頼性の低いアプローチ#4
それでは、実際に実行されているスクリプトを示していない可能性があるため、コマンドライン全体のチェックをスキップし、lsof
代わりにこのスクリプトを開いているすべてのプロセスを見つけるためにチェックするとどうなりますか?
まあ、はい、このアプローチは実際にはそれほど悪くはありません:
if otherpids="$(lsof -t "$0" | grep -vFx "$$")"; then
echo >&2 "Error: There are other processes that have this script open - most likely other copies of the script running. Exiting to avoid conflicts."
ps >&2 -fq "${otherpids//$'\n'/ }"
exit 1
fi
もちろん、スクリプトのコピーが実行されている場合、新しいインスタンスは正常に起動し、2つのコピーが実行されます。
または、実行中のスクリプトが変更された場合(Vimまたはaなどgit checkout
)、Vimとgit checkout
結果の両方が新しいファイル(新しいiノード)になるので、スクリプトの「新しい」バージョンは問題なく起動します。古いもの。
ただし、スクリプトが変更されたりコピーされたりしないのであれば、このバージョンはかなり良いです。チェックに到達する前にスクリプトファイルを既に開いている必要があるため、競合状態はありません。
別のプロセスがスクリプトファイルを開いている場合、依然として誤検出が発生する可能性がありますが、Vimで編集のために開いていても、vimは実際にスクリプトファイルを開いたままにしないため、誤検出は発生しません。
しかし、覚えて、スクリプトを編集またはコピーされる可能性があります場合はfalseを取得しますので、このアプローチを使用していないネガは一度に複数のインスタンスを実行-すなわちこれはVimで編集する種類の偽陽性を与えていないという事実は問題ないはずあなたへ。ただし、Vimでスクリプトを開いている場合、アプローチ3 は誤検知(つまり、起動を拒否)を行うためです。
それでは、何をすべきでしょうか?
この質問へのトップ投票答えが良いソリッドなアプローチを提供します。
おそらくもっと良いものを書くことができます...しかし、上記のすべてのアプローチですべての問題と警告を理解していない場合、それらをすべて回避するロック方法を書くことはできません。
kill
edのときにロックファイルを削除するためにTERMをトラップする可能性があります。また、ロックファイルに触れるだけでなく、自分のPIDをロックファイルに保存することをお勧めします。