Cercare e sostituire ricorsivamente una parola in più file

 

Il sistema operativo Linux offre molteplici strumenti per la gestione o la modifica dei file; in questo articolo mostrerò come utilizzare alcuni comandi per sostituire una o più parole all’interno di un file di testo.

Un comando piuttosto utile quando si deve sostituire una o più parole in alcuni file è questo:

sed -i ‘s/parola1/parola2/g’ *.txt

in questo modo la parola1 verrà sostituita dalla parola2 in tutti i file di testo presenti nella directory corrente.

Se però dovessimo eseguire questa sostituzione anche nei file presenti in alcune sotto cartelle allora il comando diventa:

find ./ -type f -exec sed -i ‘s/parola1/parola2/g’ {} \;

in questo caso ho fatto a meno del filtro per i file di tipo .txt e quindi verranno presi in considerazione tutti i file presenti nella directory corrente e nelle sue sottodirectory.

Con il comando find che è stata usata l’opzione “-exec”  che permette di eseguire un comando ogni volta che viene trovato un file che rispetta le regole impostate per la ricerca.

Nel caso precedente la ricerca comprende tutti gli elementi di tipo “file” ed esclude le directory.

Tutto quello che segue la direttiva “-exec” costituisce il comando da eseguire e i suoi parametri, fino al carattere “\;” che indica la fine della stringa di comando.

Un altro elemento fondamentale è il simbolo “{}” che indica il nome attuale del file trovato e che, in questo modo, essere usato come parametro dal comando che si vuole eseguire.

Nel comando precedente le parentesi graffe “{}” sono stati quotate e il carattere di fine comando è stato preceduto con uno slash “” per proteggere questi simboli dall’espansione della shell.

Il comando viene eseguito nella directory di partenza, quindi se il comando inserito prevede un output occorre tenerne conto.

Consiglio di cercare prima la parola, giusto per verificare cosa verrà trovato e sostituito:

find ./ -type f -exec grep -r “parola1” {} \;

Oppure si può usare il comando:

find ./ -type f -print0 | xargs -0 grep “parola1”

in questo modo verranno visualizzate tutte le righe che contengono la stringa indicata.

In particolare è stato usata la direttiva “-print0” che permette di avere come output il nome completo terminato da un carattere nullo. In questo modo la stringa prodotta può essere interpretata correttamente dal programma seguente.

Infatti l’output del comando find è connesso con un pipe al comando xargs il cui parametro “-0” indica che i nomi dei file ricevuti come input finiscono con un carattere nullo.

Il comando “xargs” si occupa di ricevere i nomi dei file ed eseguire il comando “grep”che a sua volta usa i parametri passati da xargs.

Se invece si vuole solo veder visualizzato il nome del file che la contiene, il comando è:

find ./ -type f -print0 | xargs -0 grep -l “parola1”

Il parametro “-l” indica che come output avremo la lista dei nomi dei file, ma non le linee, nelle sono state trovate le corrispondenze.

Faccio notare che in tutti i comandi elencati è stato ipotizzato che la ricerca avvenisse nella directory attuale e in tutte le sue sub-directory, ma se volessimo cercare in una cartella qualsiasi dovremo inserire il percorso ( relativo o assoluto):

find /home/user/ -type f | xargs grep -l “parola1”

Infine, se non fosse necessario usare dei parametri complessi per la ricerca dei file e si volesse solo ricercare ricorsivamente una parola o una frase all’interno dei file in più subdirectory, basta usare molto più semplicemente il comando grep con l’opzione “-r”:

grep “this text” *.php -r

In questo modo verrà cercata la stringa “this text” in tutti i file “.php” presenti nella directory attuale e in tutte le sue sotto directory.