Comandi in loop in Bash

Eseguire lo stesso comando su tanti file dello stesso tipo è noioso, e come ogni cosa noiosa è meglio farla eseguire ad una macchina. Per fortuna la shell bash ci permette di creare dei loop di comandi in modo facilissimo usando le keyword for
, do
e done
.
Vediamo ad esempio come visualizzare tutti i file di testo della directory corrente separandoli con una riga che contenga il loro nome:
$ ls
file.csv newfile.csv testo1.txt testo2.txt
$ for i in *.txt; do echo "### File: $i ###"; cat "$i"; done
### File: testo1.txt ###
Questo è il file di testo numero uno.
Ciao!
### File: testo2.txt ###
Questo invece è il file di testo numero due.
Riciao.
$
La sintassi in dettaglio del loop è la seguente:
for <nome variabile> in <insieme di elementi>
do <comandi da eseguire su ogni elemento - uso nome vatiabile per identificare l'elemento>
done
Il ciclo può essere scritto su una sola riga, separando i vari segmenti for/do/done con ;
, oppure posso digitarlo riga per riga e in questo caso la bash si accorgerà che sto scrivendo un loop e mi proporrà il prompt >
. Esempio:
$ for i in *.txt
> do
> echo "$i"
> done
testo1.txt
testo2.txt
$
L' <insieme di elementi>
può essere specificato sia usando il globbing (.txt o access_.log, ecc.) oppure un effettivo insieme delimitato da parentesi graffe. Esempio:
$ for NUM in {1,2,3,4,5}; do echo $NUM; done
1
2
3
4
5
Oppure può essere addirittura preso dall'output di un altro comando usando l'operatore $( )
:
$ for f in $(grep -i "ciao" *); do echo $f; done
testo1.txt:Ciao!
testo2.txt:Riciao.
$
Quindi l'uso dei loop può rendere estremamente facile una nutrita serie di compiti ripetitivi, dove ad esempio occorre lanciare lo stesso comando su una serie di file diversi. Un task lungo e noioso che diventa banale grazie alla potenza della shell!