Come eseguire un’attività quando un nuovo file viene aggiunto a una directory in Linux

Questo tutorial ti mostrerà come usare gli eventi del filesystem Linux (notifica) per ricevere una notifica ogni volta che un file appare in una directory. Potresti usarli come trigger per automatizzare le attività comuni sul tuo sistema.

Scriveremo uno script che controlla una directory e agisce sui nuovi file che vengono aggiunti. Ogni file viene compresso con gzip e spostato in un’altra directory, non appena viene rilevato. Lo script utilizza il sottosistema inotify, tramite un’utilità chiamata inotify-tools. Ma prima installiamo lo strumento e sperimentiamo.

Installazione di inotify-tools e gzip

Usa apt-get per installare questo pacchetto sul tuo sistema se stai usando Ubuntu o un’altra distribuzione basata su Debian. Su altre distribuzioni Linux, utilizza invece lo strumento di gestione dei pacchetti della tua distribuzione Linux.

sudo apt-get install inotify-tools gzip

Sperimentare con inotify-tools

Cominciamo osservando una directory e vedendo quali eventi iniziano quando arrivano nuovi file. Useremo uno strumento chiamato inotifywatch, che fa parte di inotify-tools. Crea una nuova directory chiamata “incoming”:

mkdir incoming

Inizia a guardare questa directory eseguendo il seguente comando:

inotifywatch -v incoming

Questo istruirà inotify a controllare tutti gli eventi del filesystem nella directory “in arrivo”. L’opzione -v fa sì che lo strumento stampi informazioni aggiuntive su ciò che sta facendo. Non abbiamo specificato un’opzione di timeout (-t) e il comando continuerà a raccogliere eventi fino a quando non usciremo con CTRL + C. A questo punto, il nostro terminale dovrebbe assomigliare a questo:

Apri una nuova finestra di terminale (o scheda) e passa alla directory in arrivo. Utilizza il comando touch per creare un nuovo file denominato “newfile”.

cd incoming/
touch newfile

Ora torna alla prima finestra del terminale e ferma inotifywatch premendo CTRL + C.

Una tabella degli eventi verrà pubblicata nella console, indicando un’istanza di “create”, “open”, “attrib” e “close_write”. Questi quattro eventi si sono verificati quando abbiamo utilizzato il tocco per creare un nuovo file, impostare i suoi attributi di accesso al file, aprirlo per scrivere un carattere di terminazione nullo e quindi chiuderlo in seguito. Questi sono solo alcuni della moltitudine di eventi che possono essere monitorati su un filesystem con inotify-tools. Puoi vedere l’elenco completo nella pagina principale di inotifywatch.

Per i nostri scopi siamo interessati solo a due eventi:

“Crea” – quando viene creato un file nella directory di destinazione.
“Move_to” – quando un file viene spostato da un’altra posizione nella directory di destinazione.

Proviamo di nuovo a inotifywatch, ma questa volta istruendolo a monitorare solo questi due eventi. Esegui questo comando nella prima finestra del terminale:

inotifywatch -v -e create -e moved_to incoming

Nella seconda finestra o scheda del terminale, proviamo a creare un nuovo file, a modificarne il contenuto e quindi a spostare il file da un’altra posizione alla directory di destinazione. Tutti questi comandi vengono eseguiti dalla directory home.

touch incoming/created
echo Testing123 >> incoming/created
touch /tmp/created2
mv /tmp/created2 incoming/

Torna alla prima finestra del terminale e interrompi inotifywatch premendo CTRL + C. Vedremo il seguente output:

Sono stati contati solo due eventi: la creazione di un file denominato “created.txt” e lo spostamento di un file esistente denominato “created2.txt”. Tutto il resto, come la modifica di “created.txt”, è stato ignorato.

Guardare una directory ed eseguire un’attività

Ora che sappiamo quali eventi seguire, possiamo utilizzare un altro strumento chiamato inotifywait per bloccare l’esecuzione fino a quando un file non viene creato o spostato nella nostra directory di destinazione. Useremo gli stessi argomenti che abbiamo fatto con inotifywatch e specificheremo anche come vogliamo che il nome del file sia formattato per l’uso nel nostro compito.

Prima di iniziare, abbiamo bisogno di una directory per contenere i file che sono già stati elaborati. Crea una directory chiamata “elaborata”:

mkdir processed

Successivamente, crea un nuovo script chiamato “watch-incoming.sh” e aggiungi i contenuti elencati di seguito:

#!/bin/bash

TARGET=~/incoming/
PROCESSED=~/processed/

inotifywait -m -e create -e moved_to --format "%f" $TARGET 
        | while read FILENAME
                do
                        echo Detected $FILENAME, moving and zipping
                        mv "$TARGET/$FILENAME" "$PROCESSED/$FILENAME"
                        gzip "$PROCESSED/$FILENAME"
                done

Lo script esegue il comando inotifywait con l’opzione -m. In questo modo il monitor dei comandi cambia a tempo indeterminato. Ogni volta che viene rilevato un nuovo evento, il nome del file viene passato al comando di lettura e iniettato nella variabile “FILENAME”. Viene eseguito il blocco sotto il ciclo while, in cui il file viene prima spostato nella directory “processato” e poi compresso con gzip. Il file originale viene sostituito con il file compresso e il nome del file terminerà in “.gz”.

Concediamo i permessi di esecuzione su questo script ed eseguiamolo dalla nostra home directory.

chmod u+x watch-incoming.sh
./watch-incoming.sh

Apri la seconda finestra del terminale e crea un nuovo file nella directory “incoming”. Elenca i contenuti sia della directory “in entrata” che di “elaborati” per vedere i risultati dell’evento rilevato:

Il file di testo grezzo che abbiamo copiato nella directory “in entrata” è stato rilevato dallo script, copiato in “elaborato” e quindi compresso utilizzando gzip.

Possiamo svolgere alcune attività interessanti ora che siamo in grado di guardare i nuovi file in arrivo in una directory. Ad esempio, potremmo aggiungere una filigrana ai file immagine, comprimere video non elaborati in formato mp4 e persino caricare ogni nuovo file che vediamo in un bucket Amazon S3. Questo script è un buon punto di partenza per avviare i tuoi flussi di lavoro e automatizzare le attività comuni sul tuo sistema.