/tmp
という名前のsleep.txt
ディレクトリにファイルが表示されるのを待機するシェルスクリプトを記述しようとしています。見つかった場合、プログラムは停止します。それ以外の場合は、プログラムをファイルが見つかるまでスリープ(一時停止)状態。ここで、テストコマンドを使用することを想定しています。だから、のようなもの
(if [ -f "/tmp/sleep.txt" ];
then stop
else sleep.)
私はシェルスクリプトを書くのが初めてで、どんな助けも大歓迎です!
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サイクルを浪費します。
ファイルが既に存在する場合に_touch /tmp/sleep.txt
_も登録するためにopen
イベントを含めました。
テストをwhile
ループに入れるだけです。
while [ ! -f /tmp/sleep.txt ]; do sleep 1; done
# next command
これまでに提供されたinotifywait
ベースのアプローチのいくつかには、いくつかの問題があります。
sleep.txt
に名前が変更されたsleep.txt
ファイルを見つけることができません。 create
に加えてmoved_to
イベントにも一致する必要があります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の監視をバックグラウンドに残します。 inotifywaitによって監視されるディレクトリがドット(。)から次のように変更されている場合、exactly要件(つまり、sleep.txtが/ tmp内に表示されるのを待つ)に一致する唯一の回答は、Stephaneの回答のようです。 '/ tmp'。
ただし、一時ディレクトリを使用する場合[〜#〜] only [〜#〜]を使用して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という名前を付けることができます。 anyファイルが$directoryToPutSleepFile
内に作成された瞬間、スクリプトはinotifywait
ステートメントを過ぎて続行します。
一般に、単純なテスト/スリープループ以外の信頼性を高めることは非常に困難です。主な問題は、テストがファイルの作成と競合することです。テストが繰り返されない限り、作成イベントが失われる可能性があります。これは、シェルを使用して開始するほとんどの場合に断然最善の策です。
#!/bin/bash
while [[ ! -e /tmp/file ]] ; do
sleep 1
done
パフォーマンスの問題が原因でこれで不十分であることがわかった場合は、シェルを使用することはおそらく最初から優れたアイデアではありません。
Maxschlepzigの承認された回答(および https://superuser.com/questions/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です(タイムアウトのドキュメント(マニュアルページ)のとおり)。作成/オープンされた場合、終了ステータスは0(成功)です。
はい、inotifywaitはこの方法でサブシェルで実行され、そのサブシェルは、タイムアウトが発生したとき、またはメインスクリプトが終了したとき(どちらか早い方)にのみ実行を終了します。