Nonostante sia potentissima, Bash – la shell più usata in ambienti UNIX – fino alla versione 3.0 (esclusa – changelog), non permetteva nativamente l’utilizzo di Espressioni Regolari, si poteva in qualche modo ovviare usando grep, sed, awk o expr.
Fortunatamente con la versione 3.0 è stato aggiunto il supporto nativo all’operatore =~ [fonte], che proviene dal Perl e permette un uso molto potente delle regexp, utilizzando solo le forze della nostra $SHELL.
Un esempio:
if [[ "Stringa" =~ S([a-z]+)a ]]; then
echo $BASH_REMATCH; # stampa "Stringa"
echo ${BASH_REMATCH[1]}; # stampa "tring"
fi
Capito? :)
Come potete vedere, il funzionamento è molto simile anche alla funzione preg_match in PHP, oltre allo stesso operatore del Perl: praticamente si confronta una stringa con un'espressione regolare (che deve essere indicata senza alcun apice ai bordi!), quindi se l'espressione regolare matcha la stringa, il testo corrispondente finisce nella variabile $BASH_REMATCH; qualora nell’espressione regolare si siano definite delle sottoespressioni (espressioni tra parentesi tonde, in questo caso: ([a-z]+)), allora il loro contenuto finisce in $BASH_REMATCH[$i] (con $i = 0 si intende $BASH_REMATCH stesso, mentre con $i = 1 la prima sottoespressione).
Siccome, a partire da Bash 3.2 l’espressione regolare non può essere quotata (ossia tra apici ' o "), qual’ora si analizzino stringhe con degli spazi bisogna usare l’escape . Ossia:
if [[ "Stringa bella Lunga con tanti Spazi" =~ S([a-z]+)a be.* L([a-z]*)a ]]; then
echo $BASH_REMATCH; # stampa "Stringa bella Lunga"
echo ${BASH_REMATCH[1]}; # stampa "tring"
echo ${BASH_REMATCH[2]}; # stampa "ung"
fi
Sottolineo che di default l’operatore binario è case sensitive, è tuttavia possibile usare rispettivamente shopt -s nocaseglob e shopt -u nocaseglob per attivare o disattivare il case insensitive (altre info).
Un esempio di utilizzo più pratico, nel mio caso, è stato quello di gestire alcune foto scattate col cellulare (un Motorola) leggerendo l’ora e la data di scatto dal nome del file (in formato DD-MM-YY_HHMM) e quindi salvando il timestamp nel file stesso, sia come parametro EXIF che come data di modifica.
Grazie a =~ e ad exiv2, tutto questo è stato possibile in 16 righe di script che in qualche secondo hanno sistemato oltre 650 foto… ;)