Como usar o inotifywait para assistir a um diretório para criação de arquivos de uma extensão específica

21

Eu já vi essa resposta .

Você deve considerar o uso de inotifywait, como um exemplo:

inotifywait -m /path -e create -e moved_to |
    while read path action file; do
        echo "The file '$file' appeared in directory '$path' via '$action'"
        # do something with the file
    done

Minha pergunta é que, o script acima observa um diretório para criação de arquivos de qualquer tipo, mas como modifico o inotifywaitcomando para reportar apenas quando um arquivo de determinado tipo / extensão é criado (ou movido para o diretório) - por exemplo, deve relatório quando qualquer .xmlarquivo é criado.

O QUE TENTEI:

Eu executei o inotifywait --helpcomando e li as opções da linha de comando. Possui --exclude <pattern>e --excludei <pattern>comandos para EXCLUIR arquivos de certos tipos (usando regEx), mas eu preciso de uma maneira de INCLUIR apenas os arquivos de um determinado tipo / extensão.

Tímido
fonte
BTW, o uso pathacima provavelmente não é o melhor nome de variável se você quiser brincar com isso primeiro em um shell. Se você usá-lo, não poderá usar comandos e tudo mais, pois isso basicamente substituiu o padrão PATH. Por isso, recomendo usar um nome de var alternativo, como em fpathvez disso. ou seja while read fpath action file, qualquer comando padrão normalmente disponível no seu shell ainda será.
Baptiste Mathus
é meio ridículo que não haja uma opção de inclusão.
erandros 9/09

Respostas:

17

como faço para modificar o comando inotifywait para reportar apenas quando um arquivo de determinado tipo / extensão é criado

Observe que este é um código não testado, pois não tenho acesso inotifyno momento. Mas algo parecido com isso deve funcionar:

inotifywait -m /path -e create -e moved_to |
    while read path action file; do
        if [[ "$file" =~ .*xml$ ]]; then # Does the file end with .xml?
            echo "xml file" # If so, do your thing here!
        fi
    done
maulinglawns
fonte
2
Isso funciona e eu testei com o inotifywait.
TheBetterJORT
11
Como você executa isso? É um comando único ou precisa estar em execução em loop ou algo assim? Talvez como parte de incron(espero que não).
SDsolar
@SDsolar Varia. Para mim, eu costumo correr inotify, quer com nohupou iniciá-lo com o serviço de um systemd personalizado. Na maioria das vezes o último.
maulinglawns
9

Use um duplo negativo:

inotifywait -m --exclude "[^j][^s]$" /path -e create -e moved_to |
    while read path action file; do
        echo "The file '$file' appeared in directory '$path' via '$action'"
    done

Isso incluirá apenas arquivos javascript

Jonas Earendel
fonte
11
Bom, eu gosto que ele muda a filtragem para, em inotifywaitvez de gerar uma saída enorme para todos os arquivos e filtros posteriormente (como na outra resposta). Ainda não tentei, mas acho que seria um pouco mais rápido.
TMG
Isto é exatamente o que eu estava procurando. Como modificar a --excludeentrada para observar .extarquivos. Isso é executado apenas uma vez ou em um loop for?
kurokirasama
É um daemon, então ele será executado até que ele trava ou você desligá-lo :)
Jonas Earendel
Desculpe, perdi a primeira pergunta. inotifywait -m --exclude "[^.][^e][^x][^t]$" /home/jonas/Skrivbord/test -e create -e moved_to | while read path action file; do echo "The file '$file' appeared in directory '$path' via '$action'" done Tenho certeza que o regex pode ser otimizado, mas este bebê funciona :)
Jonas Earendel
Thanxs !! Vou testá-lo!!
kurokirasama
3

Embora a abordagem dupla negativa da resposta anterior seja uma boa idéia, já que (como o TMG observou) de fato muda o trabalho de filtragem para inotifywait, ela não está correta.

Por exemplo, se um arquivo terminar as, ele não corresponderá [^j][^s]$porque a letra final snão corresponde [^s], portanto, não será excluída.

Em termos booleanos, se Sé a instrução:

"a letra final é s"

e Jé a declaração:

"a penúltima letra é j"

então o valor do --excludeparâmetro deve ser semanticamente igual a not(J and S), o que pelas leis de De Morgan é not(J) or not(S).

Outro problema potencial é que in zsh, $pathé uma variável interna que representa a matriz equivalente a $PATH, de modo que a while read path ...linha estraga completamente $PATHe faz com que tudo se torne não executável a partir do shell.

Portanto, a abordagem correta é:

inotifywait -m --exclude "[^j].$|[^s]$" /path -e create -e moved_to |
    while read dir action file; do
        echo "The file '$file' appeared in directory '$dir' via '$action'"
    done

Observe o .que é necessário depois [^j]para garantir que a correspondência seja aplicada na penúltima posição e também que o |caractere (representando o OR booleano mencionado acima) não deve ser escapado aqui, porque --excludeutiliza expressões regulares estendidas do POSIX.

Adam Spires
fonte