Isso funciona para mim:
$ 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
)
Exemplo
Para começar, criei uma estrutura de diretório de exemplo para trabalhar com:
$ mkdir -p dir1/dir2/dir{3..5}
$ tree dir1/
dir1/
└── dir2
├── afile
├── dir3
├── dir4
└── dir5
4 directories, 1 file
Eu então executei isso para começar a ver o diretório:
$ 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 )
Eu, então, executei os comandos touch afile
neste diretório:
$ cd dir1/dir2
$ touch afile
$ touch afile
Isso resultou nessa saída do inotifywait
:
count: 0 filename: dir1/dir2/ event: CLOSE_WRITE,CLOSE afile
Quando chega ao 2º "evento", sai.
Problemas e uma solução melhor
Um problema com o uso do subshell (...while ...)
no pipe é que não vemos a segunda mensagem de echo
quando o segundo evento ocorre. Não há problema, podemos simplesmente reestruturar coisas como esta:
$ 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
$
Expandido:
$ 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
$
Com uma tarefa em segundo plano
Se você tiver uma tarefa que irá bloquear dentro do loop while ...
, você pode introduzir um trap
para eliminá-la e, em segundo plano, permitir que o loop while ...
processe a entrada de inotifywait
. / p>
Exemplo:
$ 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/)
Em ação:
$ ./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
E não há vestígios do sleep
procs em segundo plano:
$ ps -eaf|grep [s]leep
$
Após o último ajuste em relação ao trap
que você pode ter percebido. Quando fazemos isso kill $(jobs -p)
ele joga lixo na tela assim, às vezes:
./notifier.bash: line 1: kill: (30301) - No such process
Podemos limpar isso assim:
trap 'kill $(jobs -p) > /dev/null 2>&1' EXIT;
Agora, quando executamos:
$ ./notifier.bash
count: 0 filename: dir1/dir2/ event: CLOSE_WRITE,CLOSE afile
count: 1 filename: dir1/dir2/ event: CLOSE_WRITE,CLOSE afile
$