Come trovare i files che contengono una specifica parola o un testo, in Linux: il comando grep
In Linux, per cercare un testo all'interno di uno o più files, possiamo utilizzare il comando grep.
Grep è uno strumento da riga di comando che consente di cercare, in uno o più file, le righe che contengono una specifica stringa e come output rende il contenuto di ciascuna di queste righe.
grep [pattern] [nomefile]
- Il primo parametro "pattern" è la parola, o frase, da cercare
- Il secondo parametro è il nome del file dove cercare la parola o frase.
Il comando restituisce il contenuto della riga (o delle righe) del file (o dei files) dove avviene il match, cioè che contengono il testo cercato.
Ad esempio, se volessi cercare la parola "prova" all'interno del file "index.html":
grep prova index.html
Il risultato sarà la riga o le righe che contengono la parola "prova". Ad esempio nel file "index.html" ci sono 2 righe che contengono questa parola
// nel caso di una prova viene eseguita questa porzione di codice
Era solo una prova
Come possiamo vedere, non appare in numero di riga... per adesso. Tra poco vedremo come ottenerlo!
Se invece volessi effettuare la ricerca in tutti i files con estensione ".html" utilizziamo questa scrittura
grep prova *.html
L'asterisco va letto così: "qualsiasi cosa" sia presente prima di ".html".
A differenza del caso precedente, verrà evidenziato anche il nome del file in cui il testo è stato trovato. In questo esempio abbiamo trovato la corrispondenza in due files
/var/www/html/miosito/index.php: // nel caso di una prova viene eseguita questa porzione di codice
/var/www/html/miosito/index.php: Era solo una prova
/var/www/html/miosito/page.php: Ecco una prova di un form
Nota: le righe vuote non sono presenti nell'output. Le ho indicate solo per facilitare la lettura.
Se dobbiamo effettuare una ricerca in una directory, ad esempio "/var/www/html", diversa da quella in cui mi trovo, ho due possibilità:
- entro prima nella directory, con "cd /var/www/html" e poi lancio il grep
- oppure indico il path assoluto del file in cui effettuare la ricerca in questo modo
grep prova /var/www/html/*.html
In questo caso cerco all'interno della directory "/var/www/html" all'interno di tutti i suoi files con estensione ".html"
Per cercare tutte le occorrenze all'interno della directory, cioè all'interno di tutti i files:
grep prova *
oppure
grep prova /var/www/html/*
Vediamo ancora un esempio: cerco la parola "bash" all'interno del file "/etc/passwd", che sappiamo contenere le password criptate degli utenti di un server linux
grep bash /etc/passwd
Il risultato ad esempio è il seguente
root:x:0:0:root:/root:/bin/bash
giulio:x:1000:1000:giulio:/home/giulio:/bin/bash
In queste prime ricerche abbiamo utilizzato il comando grep per la ricerca di un carattere letterale o di una serie di caratteri in un file.
Ad esempio, la stringa "bash" è una "espressione regolare di base" composta da quattro caratteri letterali: "b", "a", "s" e "h". Stiamo quindi dicendo a grep di cercare una stringa che ha una "b" immediatamente seguita da "a" e poi dalla "s" e infine dalla "h".
Vediamo tra poco la differenza tra una "espressione regolare di base" e una "espressione regolare estesa".
Cercare più stringhe
Per cercare più stringhe operiamo in questo modo
grep 'prova\|lezione' /var/www/html/*.html
Intanto, come puoi vedere, è sempre bene avvolgere tutti il contenuto da cercare con degli apici, singoli o doppi.
Inoltre abbiamo utilizzato il "pipe" (la stanghetta verticale) tra una parola e l'altra. Il "pipe" è equivalente ad "OR" cioè cerca una o l'altra parola.
Abbiamo fatto precedere il "pipe" da una backslash. Questo perchè il "pipe" è un meta-carattere, come ad esempio lo sono
? + { | ( )
All'interno degli apici, il contenuto è interpretato come una "espressione regolari di base", come nei nostri primi esempi, cioè grep non capisce che il "pipe" serve ad indicare un "OR" ma viene letto come un normale carattere letterale da cercare.
Per far capire a grep che il "pipe" è un meta-carattere, e cioè di considerare il contenuto degli apici come una "espressione regolare estesa", è necessario usare una backslash "\" prima del "|".
Questo è il motivo per cui stiamo effettuando l'escape all'operatore OR (il "pipe"), utilizzando la backslash .
Vediamo un esempio, molto utilizzato per chi deve leggere dei log sul server:
grep 'fatal\|error\|critical\|notice' /var/log/httpd/error.log
In questo esempio stiamo cercando le parole "fatal" "error" "critical" e "notice" all'interno del file "error.log" di Apache
Ecco il risultato: 3 righe
[Thu Apr 08 05:41:36.208602 2021] [lbmethod_heartbeat:notice] [pid 2439] AH02282: No slotmem from mod_heartmonitor
[Thu Apr 08 05:41:36.226742 2021] [mpm_prefork:notice] [pid 2439] AH00163: Apache/2.4.6 (CentOS) OpenSSL/1.0.2k-fips PHP/7.3.13 configured -- resuming normal operations
[Thu Apr 08 05:41:36.226758 2021] [core:notice] [pid 2439] AH00094: Command line: '/usr/sbin/httpd -D FOREGROUND'
L'alternativa alla backslash prima dei "pipe" è l'utilizzo del parametro "E" (maiuscolo), grazie al quale grep considera il contenuto degli apici come una "espressione regolare estesa",
grep -E 'fatal|error|critical|notice' /var/log/httpd/error.log
I parametri del comando grep
Vediamo acuni dei parametri previsti dal comando grep per migliorare le ricerca.
grep -v: se vogliamo trovare le corrispondenze inverse, ossia tutte le linee che non contengono il pattern.
grep -i: se vogliamo effettuare una ricerca di tipo case insensitive, ignorando quindi la differenza tra minuscole e maiuscole. Infatti grep, di default, fa distinzione tra maiuscole e minuscole.
grep -c: se vogliamo conoscere il numero delle corrispondenze trovate nel file.
grep -n: se vogliamo aggiungere al risultato della ricerca anche il numero della riga del file dove è stata trovato il match
I parametri possono essere combinati tra loro. Ad esempio, per avere il numero totale delle corrispondenze, ed effettuare una ricerca case insensitive, utilizziamo il parametro grep -ci
grep -ci 'error' /var/log/httpd/error.log
Vediamo un ultimo parametro di grep.
Nella ricerca fatta, grep estrare le righe che contengono la parola "error" ma anche righe che contengono parole più grandi che contengono la parola "error", come ad esempio "errorless" o "terrorist".
Per ricevere come risultato solo la parola specifica si utilizza il parametro w, ovviamente combinabile con altri parametri:
grep -w 'error' /var/log/httpd/error.log
Così facendo andiamo ad estrarre le sole righe che contengono effettivamente solo la stringa "error" intesa come una parola intera, non altre parole che la contengono.
Possiamo anche dire che la stringa "error" deve essere composta da soli "caratteri di parole". I "caratteri di parola" sono quelli che includono i simboli alfanumerici (az, AZ e 0-9) e il simbolo sottolineatura _ (underscore). Mentre tutti gli altri simboli sono considerati "caratteri non di parole".
Come effettura una ricerca nei file binari
Ultimiamo questo articolo descrivendo come cercare un testo all'interno di un file binario, utilizzando grep.
In questo caso dobbiamo concatenare il comando "string" con il comando "grep"
strings [nomefile] | grep [pattern]
Il pipe "|" significa che l'output del primo comando "strings", che precede la barra verticale, diventa l'input del secondo comando "grep".
Il comando "strings" serve a leggere i dati di uno o più file. Letti i dati, ne passiamo il contenuto al comando "grep" per la ricerca.