2番目のinotifyイベントが発生した場合、プロセスを終了する方法は?

2番目のinotifyイベントが発生した場合、プロセスを終了する方法は?
inotifywait -q -m -e close_write,create --recursive ../orgmode-parse-print | 
while read -r filename event; do
    echo $filename;
    echo $event
    sleep infinity;
done

上記の問題は永遠に「スリープ」状態であり、決して終了しないということです。sleep他のイベントが発生した場合、プロセス(デフォルトではwhileループ(含む)の内容)を終了または再開するにはどうすればよいですか?

つまり、コマンドを実行して終了し(割り込みであると仮定)、ファイルが変更されたら再起動します。

sleepここではこれを例として使用します。実行中の実際のプロセスは長期実行プロセスです。

ベストアンサー1

これは私にとって効果的です。

$ inotifywait -q -m -e close_write,create --recursive dir1/ | \
  ( 
    CNT=0; 
    while read -r filename event; do 
       echo "count: $CNT filename: $filename  event: $event"; ((CNT++)); 
       [ "$CNT" -eq 1 ] && exit; 
    done 
  )

はい

まず、サンプルディレクトリ構造を作成しました。

$ mkdir -p dir1/dir2/dir{3..5}

$ tree dir1/
dir1/
└── dir2
    ├── afile
    ├── dir3
    ├── dir4
    └── dir5

4 directories, 1 file

その後、これを実行してディレクトリの表示を開始します。

$ inotifywait -q -m -e close_write,create --recursive dir1/ | ( CNT=0; while read -r filename event; do echo "count: $CNT filename: $filename  event: $event"; ((CNT++)); [ "$CNT" -eq 1 ] && exit; done )

次に、touch afileこのディレクトリからコマンドを実行します。

$ cd dir1/dir2
$ touch afile
$ touch afile

結果は次のとおりですinotifywait

count: 0 filename: dir1/dir2/  event: CLOSE_WRITE,CLOSE afile

2番目の「イベント」に達すると終了します。

問題とより良い解決策

(...while ...)echoパイプにサブシェルを使用する場合の1つの問題は、2番目のイベントが発生したときに2番目のメッセージが表示されないことです。問題ありません。次のように簡単にリファクタリングできます。

$ CNT=0; while read -r filename event; do echo "count: $CNT filename: $filename  event: $event"; ((CNT++)); [ "$CNT" -eq 2 ] && break; done < <(inotifywait -q -m -e close_write,create --recursive dir1/)
count: 0 filename: dir1/dir2/  event: CLOSE_WRITE,CLOSE afile
count: 1 filename: dir1/dir2/  event: CLOSE_WRITE,CLOSE afile
$

拡張:

$ CNT=0; \
  while read -r filename event; do \
    echo "count: $CNT filename: $filename  event: $event"; ((CNT++)); \
    [ "$CNT" -eq 2 ] && break; \
  done < <(inotifywait -q -m -e close_write,create --recursive dir1/)
count: 0 filename: dir1/dir2/  event: CLOSE_WRITE,CLOSE afile
count: 1 filename: dir1/dir2/  event: CLOSE_WRITE,CLOSE afile
$

バックグラウンドタスクがあります

while ...ループ内でブロックされているアクションがある場合は、それらを導入して終了し、ループが処理できるようにtrapバックグラウンドに配置できます。while ...inotifywait

例:

$ cat ./notifier.bash
#!/bin/bash

trap 'kill $(jobs -p)' EXIT;

CNT=0
while read -r filename event; do
  sleep 1000 &
  echo "count: $CNT filename: $filename  event: $event"; ((CNT++))
  [ "$CNT" -eq 2 ] && break
done < <(inotifywait -q -m -e close_write,create --recursive dir1/)

実行中:

$ ./notifier.bash
count: 0 filename: dir1/dir2/  event: CLOSE_WRITE,CLOSE afile
count: 1 filename: dir1/dir2/  event: CLOSE_WRITE,CLOSE afile
./notifier.bash: line 1: kill: (30301) - No such process

sleepそしてバックグラウンドプロセスの残りの部分はありません。

$ ps -eaf|grep [s]leep
$

trap最後の調整について皆さんも気づいたでしょう。これにより、kill $(jobs -p)次のように画面にゴミが投げられます。時には次のようになります。

./notifier.bash: line 1: kill: (30301) - No such process

次のように整理できます。

 trap 'kill $(jobs -p) > /dev/null 2>&1' EXIT;

今実行すると:

$ ./notifier.bash
count: 0 filename: dir1/dir2/  event: CLOSE_WRITE,CLOSE afile
count: 1 filename: dir1/dir2/  event: CLOSE_WRITE,CLOSE afile
$

引用する

おすすめ記事