Cum se utilizează inotifywait pentru a supraveghea un director pentru crearea de fișiere cu o anumită extensie (Unix, Script Shell, Shell, Sisteme De Fișiere, Monitorizare, Inotify)

Timid a intrebat.

Am văzut acest răspuns.

Ar trebui să luați în considerare utilizarea inotifywait, ca exemplu:

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

Întrebarea mea este că, scriptul de mai sus urmărește un director pentru crearea de fișiere de orice tip, dar cum pot modifica inotifywait pentru a raporta numai atunci când un fișier de un anumit tip/extensie este creat (sau mutat în director) – de exemplu, ar trebui să raporteze atunci când orice .xml fișier este creat.

CE AM ÎNCERCAT:

Am rulat comanda inotifywait --help și am citit opțiunile din linia de comandă. A --exclude <pattern> și --excludei <pattern> comenzi pentru EXCLUDE fișiere de anumite tipuri (prin utilizarea regEx), dar am nevoie de o modalitate de a INCLUDE doar fișierele de un anumit tip/extensie.

Comentarii

  • De asemenea, folosind path de mai sus nu este probabil cel mai bun nume de variabilă dacă doriți să vă jucați cu acest lucru mai întâi într-un shell. Dacă îl folosiți, atunci nu veți putea folosi comenzi și tot ce trebuie, deoarece acest lucru practic tocmai a înlocuit standardul PATH. Prin urmare, vă recomand să folosiți un nume de variabilă alternativ, cum ar fi fpath de exemplu while read fpath action file atunci orice comandă standard disponibilă de obicei din shell-ul dvs. va fi în continuare. –  > Por Baptiste Mathus.
  • este oarecum ridicol că nu există o opțiune de includere. –  > Por erandros.
  • În cele din urmă au adăugat o opțiune –include, conform răspunsului lui @ericcurtin de mai jos. –  > Por Adam Spiers.
6 răspunsuri
maulinglawns

cum pot modifica comanda inotifywait pentru a raporta numai atunci când este creat un fișier de un anumit tip / extensie

Vă rugăm să rețineți că acest lucru este un cod netestat deoarece nu am acces la inotify chiar acum. Dar ceva asemănător cu acest lucru ar trebui să funcționeze:

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

Comentarii

  • Acest lucru funcționează și l-am testat cu inotifywait. –  > Por TheBetterJORT.
  • Cum se execută acest lucru? Este o comandă care se execută o singură dată sau trebuie să fie rulată într-o buclă sau ceva de genul acesta? Poate ca parte a incron (sper că nu). –  > Por SDsolar.
  • @SDsolar Acesta variază. În cazul meu, de obicei, rulează inotify fie cu nohup fie îl pornesc cu un serviciu systemd personalizat. De cele mai multe ori cel din urmă. –  > Por maulinglawns.
  • care este diferența dintre inotify și inotifywait? – user359907
tofsjonas

Utilizați o dublă negație:

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

Aceasta va include doar fișierele javascript

Comentarii

  • Frumos, îmi place că mută filtrarea la inotifywait în loc să genereze o ieșire uriașă pentru toate fișierele și să filtreze ulterior (ca în celălalt răspuns). Nu am încercat, dar cred că ar funcționa puțin mai rapid. –  > Por TMG.
  • Este exact ceea ce căutam. Cum se poate modifica --exclude intrare pentru a urmări .ext fișiere. Acest lucru se execută o singură dată sau într-o buclă for? –  > Por kurokirasama.
  • Este un daemon, deci va rula până când se blochează sau până când îl închizi 🙂 –  > Por tofsjonas.
  • Scuze, am ratat prima întrebare. 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 Sunt sigur că regex-ul poate fi optimizat, dar acest copil funcționează 🙂 –  > Por tofsjonas.
  • După cum notează @AdamSpiers, acest răspuns este incorect, deoarece s-ar declanșa la orice fișier care se termină în jX sau Xs (.ja, .jb, .jc… ..as, .bs. .cs…) –  > Por Fabien Snauwaert.
Adam Spiers

În timp ce abordarea dublu-negativă din răspunsul anterior este o idee bună, deoarece (așa cum a observat TMG) transferă într-adevăr sarcina de filtrare către inotifywait, , nu este corectă.

De exemplu, dacă un fișier se termină în as atunci nu se va potrivi cu [^j][^s]$ deoarece litera finală s nu se potrivește cu [^s], Prin urmare, nu va fi exclus.

În termeni booleeni, dacă S este afirmația:

„litera finală este s

și J este afirmația:

„penultima literă este j

atunci valoarea lui --exclude ar trebui să echivaleze semantic cu not(J and S), , care prin legile lui De Morgan este not(J) or not(S).

O altă problemă potențială este că în zsh, , $path este o variabilă încorporată care reprezintă echivalentul matricei $PATH, , astfel încât while read path ... linia va încurca complet $PATH și va face ca totul să devină neexecutabil din shell.

Prin urmare, abordarea corectă este:

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

Observați că . care este necesar după [^j] pentru a se asigura că potrivirea este aplicată în penultima poziție și, de asemenea, că linia | (care reprezintă caracterul boolean OR menționat mai sus) nu ar trebui să fie scăpat aici, deoarece --exclude acceptă expresii regulate extinse POSIX.

Cu toate acestea, vă rugăm să consultați și să voteze în sus răspunsul lui @ericcurtin, care pentru versiunile mai noi de inotifywait este o abordare mult mai curată.

Comentarii

  • Ce se întâmplă dacă codul dvs. este cod C și doriți să includeți fișiere .c și .h –  > Por ericcurtin.
  • --exclude '[^ch]$|[^.].$' ar trebui să realizeze acest lucru (deși nu am testat). –  > Por Adam Spiers.
ericcurtin

–include și –includei sunt opțiuni reale cel puțin în versiunea principală a binariilor:

https://github.com/inotify-tools/inotify-tools/tree/master

Comentarii

  • Aceasta este de departe cea mai bună abordare acum, în ciuda faptului că în prezent este mai puțin votată decât celelalte răspunsuri. –  > Por Adam Spiers.
  • Aparent, opțiunile include sunt disponibile doar începând cu versiunea 3.20.1. –  > Por Fabien Snauwaert.
Fabien Snauwaert

Începând cu inotifywait versiunea 3.20.1 puteți utiliza un --include opțiune.

Exemplu de inotifywait cu --include

Iată un exemplu care utilizează --include pentru a rula un script atunci când un fișier wav este adăugat la un director.

#!/bin/sh

# Usage
#
# Call the script with the directory you want to watch as an argument. e.g.:
# watchdir.sh /app/foo/
#
#
# Description:
# Uses inotifywait to look for new files in a directory and process them:
# inotifywait outputs data which is passed (piped) to a do for subcommands.
#
#
# Requirements:
# Requires inotifywait which is part of inotify-tools.
# e.g. yum install -y inotify-tools or apt-get install -y inotify-tools.
#
#
# See also:
# https://linux.die.net/man/1/inotifywait
# https://github.com/inotify-tools/inotify-tools/wiki#info
# (Might be interested in pyinotify too.)


echo "Watch $1 for file changes..."


# Be careful not to confuse the output of `inotifywait` with that of `echo`.
# e.g. missing a `` would break the pipe and write inotifywait's output, not
# the echo's.
inotifywait 
  $1 
  --monitor 
  -e create 
  --timefmt '%Y-%m-%dT%H:%M:%S' 
  --format '%T %w %f %e' 
  --include ".wav" 
| while read datetime dir filename event; do
  echo "Event: $datetime $dir$file $event"
  echo "Now, we could pass $datetime $dir $filename and $event to some other command."

  echo "Here's the extensionless filename:" ${filename%.*}
  echo "And the extension if needed:" ${filename##*.}

  python3 /app/phono.py --custom $dir$filename $dir${filename%.*}.txt /tmp/${filename%.*}
done


# --format:
#   %T  Replaced with the current Time in the format specified by the --timefmt option, which should be a format string suitable for passing to strftime(3).
#   %w  This will be replaced with the name of the Watched file on which an event occurred.
#   %f  When an event occurs within a directory, this will be replaced with the name of the File which caused the event to occur. Otherwise, this will be replaced with an empty string.
#   %e  Replaced with the Event(s) which occurred, comma-separated.
#   %Xe Replaced with the Event(s) which occurred, separated by whichever character is in the place of 'X'.
#
# There's no --include option, but there's --exclude, which can be used to the same effect as an include.


# test the script by creating a file in the watched directory, e.g.
# touch /app/foo/file1.wav # will trigger the script
# touch /app/foo/file1.txt # will not trigger the script

Instalarea (sau compilarea) inotify-tools

inotifywait face parte din inotify-tools. Îl puteți instala prin metoda obișnuită, de exemplu:

apt-get install -y inotify-tools

sau

yum install -y inotify-tools

Dar, dacă sunt disponibile doar versiuni mai vechi din depozite, este posibil să doriți să compilați din sursă. În acest caz:

cd /tmp/inotify-tools/
wget https://github.com/inotify-tools/inotify-tools/releases/download/3.20.2.2/inotify-tools-3.20.2.2.tar.gz
tar xzvf inotify-tools-3.20.2.2.tar.gz
cd inotify-tools-3.20.2.2
./configure --prefix=/usr --libdir=/lib64
make
make install

Matt

În cazul meu, încercam să filtrez ieșirea lui inotifywait folosind ceva de genul grep, pentru a aștepta crearea unui singur fișier cu o anumită extensie. Problema cu această abordare este că grep se blochează pur și simplu.

Dintr-un motiv oarecare, un semnal SIGPIPE fie nu este trimis, fie nu este procesat de către inotifywait. Am găsit această întrebare, care s-a confruntat cu aceeași problemă pe care am avut-o eu, iar substituirea procesului poate fi folosită ca o soluție de rezolvare:

grep -E .*iso -m1 < <(inotifywait -qm -e create .)

Substituția de proces nu funcționează în anumite shell-uri (de ex. sh), așa că această metodă nu funcționează în toate cazurile.


Din celelalte răspunsuri date, nu am putut găsi opțiunea –include. Probabil că voi experimenta cu –exclude.

Comentarii

  • Dacă versiunea dvs. nu are --include, , este prea veche și ar trebui să vedeți dacă puteți face un upgrade, deoarece dacă puteți, aceasta va fi de departe cea mai ușoară soluție. –  > Por Adam Spiers.
  • Am descărcat o versiune nouă, care nu o are. Văd că --include acum în codul sursă, totuși, în codul sursă. Inițial mă uitam la github.com/inotify-tools/inotify-tools/blob/master/man/… , care nu menționează --include în același mod în care menționează --exclude. –  > Por Matt.
  • Conform unui alt răspuns de pe această pagină, aveți nevoie de cel puțin 3.20.1. –  > Por Adam Spiers.