回答:
Linuxでは、inotifyカーネルサブシステムを使用して、ディレクトリ内のファイルの出現を効率的に待つことができます。
while read i; do if [ "$i" = sleep.txt ]; then break; fi; done \
< <(inotifywait -e create,open --format '%f' --quiet /tmp --monitor)
# script execution continues ...
(<()
出力リダイレクト構文のBashを想定)
次のような固定時間間隔ポーリングと比較したこのアプローチの利点
while [ ! -f /tmp/sleep.txt ]; do sleep 1; done
# script execution continues ...
カーネルがより多くスリープするということです。create,open
スクリプトのようなinotifyイベント仕様で/tmp
は、下のファイルが作成または開かれたときに実行されるようにスケジュールされます。固定の時間間隔ポーリングでは、時間の増分ごとにCPUサイクルが無駄になります。
ファイルが既に存在する場合open
にも登録するイベントを含めましたtouch /tmp/sleep.txt
。
inotifywait -e create,open --format '%f' --quiet /tmp/sleep.txt --monitor > /dev/null ; # continues once /tmp/sleep.txt is created/opened
ですか?
inotifywait
それ自体はwhileループであり、ファイルが開かれる/作成されるたびに行を出力します。したがって、変更されたときにブレークするにはwhileループが必要です。
sleep.txt
、ある時点で生成されるプロセスを開始する前にスニペットを実行することを前提としています。したがって、競合状態はありません。質問には、想定しているシナリオを示唆するものは含まれていません。
inotifywait
これまでに説明したいくつかのベースのアプローチには、いくつかの問題があります。
sleep.txt
は最初に一時的な名前として作成され、次に名前が変更されたファイルを見つけることができませんsleep.txt
。moved_to
さらに、イベントに一致する必要がありますcreate
sleep.txt
は、が作成されたかどうかを判断するのに十分ではありません。foo\nsleep.txt\nbar
たとえば、ファイルが作成された場合はどうなりますか?inotifywait
か?その後inotifywait
、すでにここにあるファイルを永遠に待ちます。時計をインストールした後、ファイルがまだ存在していないことを確認する必要があります。inotifywait
ファイルが検出された後(少なくとも別のファイルが作成されるまで)実行を続けます。これらに対処するには、次のようにします。
sh -c 'echo "$$" &&
LC_ALL=C exec inotifywait -me create,moved_to --format=/%f/ . 2>&1' | {
IFS= read pid &&
while IFS= read -r line && [ "$line" != "Watches established." ]; do
: wait for watches to be established
done
[ -e sleep.txt ] || [ -L sleep.txt ] || grep -qxF /sleep.txt/ && kill "$pid"
}
sleep.txt
現在のディレクトリでの作成を監視していることに注意してください.
(したがってcd /tmp || exit
、この例では前に作成します)。現在のディレクトリは変更されないため、そのパイプラインが正常に戻ると、sleep.txt
作成されたのは現在のディレクトリになります。
もちろん、あなたは置き換えることができ.
て/tmp
上記と同じですが、一方でinotifywait
実行されて、/tmp
何度か名前が変更されている可能性(のための可能性は低い/tmp
ので、時にパイプラインが戻るが、それはないかもしれませんが、何かが一般的なケースで検討する)または新しいファイルシステムは、それに取り付けられましたこと/tmp/sleep.txt
が作成されましたが、その/new-name-for-the-original-tmp/sleep.txt
代わりに。/tmp
間隔内に新しいディレクトリが作成されることもあり、そのディレクトリは監視sleep.txt
されないため、そこに作成されたディレクトリは検出されません。
受け入れられた答えは実際に動作します(maxschlepzigに感謝します)が、スクリプトが終了するまでバックグラウンドでinotifywait監視を残します。一致していることを唯一の答えを正確にあなたの要件は(すなわち内部に/ tmpを表示するsleep.txtを待っている)がinotifywaitによって監視されるディレクトリは、ドットから変更された場合、ステファンさんのようです(。)「/ tmp」のに。
ただし、sleep.txtフラグを置くために一時ディレクトリのみを使用し、他の誰もそのディレクトリにファイルを置かないことを賭けることができる場合は、ファイルの作成についてこのディレクトリを監視するようinotifywaitに要求するだけで十分です。
最初のステップ:監視するディレクトリを作成します。
directoryToPutSleepFile=$(mktemp -d)
2番目のステップ:ディレクトリが実際にあることを確認します
until [ -d $directoryToPutSleepFile ]; do sleep 0.1; done
3番目のステップ:ファイルが内部に現れるまで待ちます $directoryToPutSleepFile
inotifywait -e create --format '%f' --quiet $directoryToPutSleepFile
配置するファイルには$directoryToPutSleepFile
、sleep.txt awake.txtという名前を付けることができます。瞬間任意のファイルが内部で作成された$directoryToPutSleepFile
スクリプトが過ぎていきますinotifywait
陳述。
sleep.txt
2つのinotifywait呼び出しの間にファイルが作成されるため、ファイルの作成を見逃す可能性があります。
sleep.txt
が作成されるまで、数回呼び出されます。たとえばtouch /tmp/foo /tmp/sleep.txt
、を試してから、1つのインスタンスinotifywait
が報告foo
して終了します。次のinotifywaitが開始されるまでに、sleep.txtがすでに存在しているため、inotifywaitはその作成を検出しません。
一般に、単純なテスト/スリープループ以外の信頼性を高めることは非常に困難です。主な問題は、テストがファイルの作成と競合することです-テストが繰り返されない限り、作成イベントは見逃される可能性があります。これは、シェルを使用して開始するほとんどの場合、最善の方法です。
#!/bin/bash
while [[ ! -e /tmp/file ]] ; do
sleep 1
done
パフォーマンスの問題のためにこれが不十分であることがわかった場合、最初にシェルを使用することはおそらく素晴らしい考えではありません。
maxschlepzigの受け入れ答え(とで受け入れ答えからの考えに基づき/superuser/270529/monitoring-a-file-until-a-string-is-found)私は(以下は、改善提案します私の見解では)タイムアウトでも動作する答え:
# Enable pipefail, so if the left side of the pipe fails it does not get silently ignored
set -o pipefail
( timeout 120 inotifywait -e create,open --format '%f' --quiet /tmp --monitor & ) | while read i; do if [ "$i" == 'sleep.txt' ]; then break; fi; done
EXIT_STATUS=$?
if [ "${EXIT_STATUS}" == '124' ]; then
echo "Timeout happened"
fi
指定されたタイムアウト内にファイルが作成/開かない場合、終了ステータスは124です(タイムアウトのドキュメント(manページ)による)。作成/開かれた場合、終了ステータスは0(成功)です。
はい、inotifywaitはこの方法でサブシェルで実行され、そのサブシェルはタイムアウトが発生するか、メインスクリプトが終了したとき(どちらか早い方)にのみ実行を終了します。
$MAILPATH
。