Introduzione

Il comando grep che sta per "global regular expression print" è uno dei comandi più potenti e comunemente usati in Linux.

Grep cerca uno o più file di input alla ricerca di linee che corrispondono a un determinato modello e scrive ciascuna riga corrispondente sullo standard output. Se non viene specificato alcun file, grep legge l'input standard, che di solito è l'output di un altro comando.

In questo tutorial, ti mostreremo come usare il comando grep attraverso esempi pratici e spiegazioni dettagliate delle opzioni grep GNU più comuni.

Sintassi del comando Grep

Prima di andare su come utilizzare il comando grep, iniziamo esaminando la sintassi di base.

La sintassi di grep assume la seguente forma:

grep [OPTIONS] PATTERN [FILE...]

Gli elementi tra parentesi quadre sono opzionali.

  • OPTIONS- Zero o più opzioni. Grep offre una serie di opzioni che ne controllano il comportamento.
  • PATTERN - Modello di ricerca.
  • FILE - Zero o più nomi di file di input.

Per poter cercare il file, l'utente che esegue il comando deve avere accesso in lettura al file.

Come utilizzare grep per cercare una stringa nei file

L'uso più basilare del comando grep è la ricerca di una stringa (text) in un file.

Ad esempio, per visualizzare le righe dal file /etc/passwd contenente la stringa bash è possibile utilizzare il comando seguente:

grep bash /etc/passwd

L'output dovrebbe assomigliare a questo:

root:x:0:0:root:/root:/bin/bash
noviello:x:1000:1000:noviello:/home/noviello:/bin/bash

Se la stringa include spazi, è necessario racchiuderla tra virgolette singole o doppie:

grep "Gnome Display Manager" /etc/passwd

Invert Match (Escludi)

Per visualizzare le linee che non corrispondono al valore cercato, utilizzare l'opzione -v(o --invert-match).

Ad esempio, per visualizzare le righe del file /etc/passwd che non contengono la stringa nologin è possibile utilizzare il comando seguente:

grep -v nologin /etc/passwd
root:x:0:0:root:/root:/bin/bash
colord:x:124:124::/var/lib/colord:/bin/false
git:x:994:994:git daemon user:/:/usr/bin/git-shell
noviello:x:1000:1000:noviello:/home/noviello:/bin/bash

Come usare Grep per cercare una stringa nell'output dei comandi

Invece di specificare i file di input, è possibile reindirizzare l'output di un altro comando verso grep e quindi visualizzare solo le righe corrispondenti a un determinato modello.

Ad esempio, per scoprire quali processi sono in esecuzione sul sistema come utente, www-data è possibile utilizzare il comando ps seguente :

ps -ef | grep www-data
www-data 18247 12675  4 16:00 ?        00:00:00 php-fpm: pool www
root     18272 17714  0 16:00 pts/0    00:00:00 grep --color=auto --exclude-dir=.bzr --exclude-dir=CVS --exclude-dir=.git --exclude-dir=.hg --exclude-dir=.svn www-data
www-data 31147 12770  0 Oct22 ?        00:05:51 nginx: worker process
www-data 31148 12770  0 Oct22 ?        00:00:00 nginx: cache manager process

Puoi anche concatenare più pipe su comando. Come puoi vedere nell'output sopra c'è anche una riga che contiene il processo grep. Se non si desidera visualizzare quella riga, passare l'output a un'altra istanza grep, come mostrato di seguito.

ps -ef | grep www-data | grep -v grep
www-data 18247 12675  4 16:00 ?        00:00:00 php-fpm: pool www
root     18272 17714  0 16:00 pts/0    00:00:00 grep --color=auto --exclude-dir=.bzr --exclude-dir=CVS --exclude-dir=.git --exclude-dir=.hg --exclude-dir=.svn www-data
www-data 31147 12770  0 Oct22 ?        00:05:51 nginx: worker process
www-data 31148 12770  0 Oct22 ?        00:00:00 nginx: cache manager process

Ricerca ricorsiva (Recursive Search)

Per cercare in modo ricorsivo un modello utilizzare, utilizzare l'opzione -r (o --recursive). Questo cercherà tra tutti i file nella directory specificata, saltando i collegamenti simbolici che si incontrano in modo ricorsivo. Per seguire tutti i collegamenti simbolici, utilizzare l'opzione -R (o --dereference-recursive).

Nel seguente esempio stiamo cercando la stringa noviello.it in tutti i file all'interno della directory /etc:

grep -r noviello.it /etc

Il comando stamperà le righe corrispondenti precedute dal percorso completo del file.

/etc/hosts:127.0.0.1 node2.noviello.it
/etc/nginx/sites-available/noviello.it:    server_name noviello.it   www.noviello.it;

Se invece di usare l'opzione -r usi l'opzione -R il comando grep seguirai tutti i collegamenti simbolici:

grep -R noviello.it /etc

Si noti l'ultima riga dell'output. Quella riga non viene stampata nell'esempio sopra perché i file all'interno della directory sites-enabled di Nginx sono collegamenti simbolici ai file di configurazione all'interno della directory sites-available.

/etc/hosts:127.0.0.1 node2.noviello.it
/etc/nginx/sites-available/noviello.it:    server_name noviello.it   www.noviello.it;
/etc/nginx/sites-enabled/noviello.it:    server_name noviello.it  www.noviello.it;

Mostra solo il Filename

Per sopprimere l'output grep predefinito e stampare solo i nomi dei file contenenti il ​​modello corrispondente, è possibile utilizzare l'opzione -l(o --files-with-matches).

Ad esempio, per cercare tra tutti i file che terminano con .conf nella directory di lavoro corrente e stampare solo i nomi dei file contenenti il tipo di stringa noviello.it:

grep -l noviello.it *.conf

L'output sarà simile al seguente:

tmux.conf
haproxy.conf

L'opzione -l viene generalmente utilizzata in combinazione con l'opzione ricorsiva -R:

grep -Rl noviello.it /tmp

Ricerca senza distinzione tra maiuscole e minuscole (Insensitive)

Per impostazione predefinita, il comando grep fa distinzione tra maiuscole e minuscole. Ciò significa che i caratteri maiuscoli e minuscoli sono trattati come distinti.

Per ignorare il caso durante la ricerca, utilizzare l'opzione -i (o --ignore-case).

Ad esempio, quando si cerca Zebra senza alcuna opzione, il comando seguente non mostrerà alcun output, ovvero ci sono linee corrispondenti:

grep Zebra /usr/share/words

Ma se esegui una ricerca senza distinzione tra maiuscole e minuscole utilizzando l'opzione -i, corrisponderà alle lettere maiuscole e minuscole:

grep -i Zebra /usr/share/words

Specificare "Zebra" corrisponderà a "zebra", "ZEbrA" o qualsiasi altra combinazione di lettere maiuscole e minuscole per quella stringa.

zebra
zebra's
zebras

Ricerca di parole complete

Durante la ricerca di "gnu", grep stamperà le righe in cui "gnu" è incorporato in parole più grandi, come "cygnus" o "magnum".

grep gnu /usr/share/words
cygnus
gnu
interregnum
lgnu9d
lignum
magnum
magnuson
sphagnum
wingnut

Per restituire solo quelle righe in cui la stringa specificata è una parola intera (racchiusa da caratteri non di parole), utilizzare l'opzione -w(o --word-regexp).

I caratteri di parola includono caratteri alfanumerici (a-z, A-Z e 0-9) e caratteri di sottolineatura (_). Tutti gli altri caratteri sono considerati caratteri non di parole.

Se si esegue lo stesso comando di cui sopra, inclusa l'opzione -w, il comando grep restituirà solo quelle righe in cui gnu è incluso come parola separata.

grep -w gnu /usr/share/words
gnu

Mostrare numeri di riga

Per mostrare il numero delle linee che contengono una stringa che corrisponde a un modello, utilizzare l'opzione -n(o --line-number). Quando si utilizza questa opzione, grep stamperà le corrispondenze sull'output standard con prefisso con il numero di riga sul quale è stata trovata.

Ad esempio, per visualizzare le righe dal file /etc/services contenente la stringa bash con il prefisso con il numero di riga corrispondente è possibile utilizzare il comando seguente:

grep -n 10000 /etc/services

L'output di seguito mostra che le corrispondenze si trovano sulle righe 10423 e 10424.

10423:ndmp            10000/tcp
10424:ndmp            10000/udp

Conteggio risultati

Per stampare un conteggio delle righe corrispondenti all'output standard, utilizzare l'opzione -c(o --count).

Nell'esempio seguente, stiamo contando il numero di account che hanno /usr/bin/zsh come shell.

grep -c '/usr/bin/zsh' /etc/passwd
3

Cercare più stringhe (pattern)

È possibile unire due o più modelli di ricerca utilizzando l'operatore OR |.

Per impostazione predefinita, grep interpreta il modello come un'espressione regolare di base in cui i meta-caratteri come | perdono il loro significato speciale e devono essere utilizzate le loro versioni rovesciate.

Nell'esempio riportato di seguito stiamo cercando tutte le occorrenze delle parole fatal, error e critical nel file di registro di errore di Nginx:

grep 'fatal\|error\|critical' /var/log/nginx/error.log

Se si utilizza l'opzione di espressione regolare estesa -E(o --extended-regexp), l'operatore | non deve essere salvato, come mostrato di seguito:

grep -E 'fatal|error|critical' /var/log/nginx/error.log

Modalità silenziosa

Il -q(o --quiet) dice grep di non scrivere nulla sul terminale (output standard). Se viene trovata una corrispondenza, il comando uscirà con lo stato 0. Ciò è utile quando si utilizza grep nella shell in cui si desidera verificare se un file contiene una stringa ed eseguire una determinata azione in base al risultato.

Ecco un esempio dell'uso di grep in modalità non interattiva come comando di test in un'istruzione if:

if grep -q PATTERN filename
then
    echo pattern found
else
    echo pattern not found
fi

Espressione regolare di base (Basic Regular Expression)

GNU Grep ha due set di funzioni per le espressioni regolari, Basic ed Extended. Per impostazione predefinita, grep interpreta il modello come un'espressione regolare di base.

Se utilizzati nella modalità di espressione regolare di base, tutti gli altri caratteri tranne i meta-caratteri sono in realtà espressioni regolari corrispondenti a se stessi. Di seguito è riportato un elenco dei meta-caratteri più comunemente usati:

Utilizzare il simbolo ^ (caret) per abbinare l'espressione all'inizio di una riga. Nel seguente esempio, la stringa ^kangaroo corrisponderà solo se si verifica all'inizio di una riga.

grep "^kangaroo" file.txt

Utilizzare il simbolo $ (dollaro) per abbinare l'espressione alla fine di una riga. Nel seguente esempio, la stringa kangaroo$ corrisponderà solo se si verifica alla fine di una riga.

grep "kangaroo$" file.txt

Utilizzare il . simbolo (punto) per abbinare un singolo carattere. Ad esempio, per abbinare tutto ciò che inizia con kan poi ha due caratteri e termina con la stringa roo, puoi usare il seguente modello:

grep "kan..roo" file.txt

Utilizzare [ ](parentesi) per abbinare qualsiasi carattere singolo racchiuso tra parentesi. Ad esempio, trova le righe che contengono accept o  accent, puoi utilizzare il seguente modello:

grep "acce[np]t" file.txt

Utilizzare [^ ] (parentesi) per abbinare qualsiasi carattere singolo racchiuso tra parentesi. Il seguente schema corrisponderà a qualsiasi combinazione di stringhe contenente co(any_letter_except_l)a, come coca, cobalt e così via, ma non corrisponderà le linee contenenti cola,

grep "co[^l]a" file.txt

Per fare un escape di un carattere speciale successivo, utilizzare il simbolo \ (barra rovesciata).

Espressioni regolari estese (Extended Regular Expressions)

Per interpretare il pattern come un'espressione regolare estesa, utilizzare l'opzione -E(o --extended-regexp). Le espressioni regolari estese includono tutti i meta-caratteri di base, insieme a meta-caratteri aggiuntivi per creare schemi di ricerca più complessi e potenti. Di seguito sono riportati alcuni esempi:

Abbina ed estrai tutti gli indirizzi email da un determinato file:

grep -E -o "\b[A-Za-z0-9._%+-][email protected][A-Za-z0-9.-]+\.[A-Za-z]{2,6}\b" file.txt

Abbina ed estrai tutti gli indirizzi IP validi da un determinato file:

grep -E -o '(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)' file.txt

L' -oopzione viene utilizzata per stampare solo la stringa corrispondente.

Stampare righe prima di un risultato

Per stampare un numero specifico di righe prima di abbinare le righe, utilizzare l'opzione -B(o --before-context).

Ad esempio, per visualizzare cinque righe di contesto iniziale prima di abbinare le righe, utilizzare il comando seguente:

grep -B 5 root /etc/passwd

Stampare righe dopo un risultato

Per stampare un numero specifico di righe dopo aver abbinato le righe, utilizzare l'opzione -A(o --after-context).

Ad esempio, per visualizzare cinque righe di contesto finale dopo aver abbinato le righe, utilizzare il comando seguente:

grep -A 5 root /etc/passwd

Conclusione

Il comando grep consente di cercare un modello all'interno dei file. Se viene trovata una corrispondenza, grep stamperà le linee contenenti il ​​motivo specificato.