Informazione su comando grep

Linguaggi di programmazione: php, perl, python, C, bash e tutti gli altri.
Simenon
Prode Principiante
Messaggi: 14
Iscrizione: venerdì 19 marzo 2021, 10:23
Desktop: Mint
Distribuzione: Mint
Sesso: Maschile
Località: Bologna

Informazione su comando grep

Messaggio da Simenon »

Ciao a tutti, avevo bisogno di greppare da un file di log tutti gli indirizzi IP lì contenuti.
In rete ho trovato questo comando con questa espressione regolare che fa molto bene il suo mestiere.

Codice: Seleziona tutto

grep -E '\b[0-9]{1,3}(\.[0-9]{1,3}){3}
Volevo chiedervi se qualcuno potesse per favore spiegarmi meglio la sintassi.
Che il comando sia settato in modo da cercare quattro cifre di tre numeri* separate da un punto, mi è chiaro, ma vi chiedo se riuscite a descrivermi meglio i punti.
Purtroppo di espressioni regolare ne capisco il giusto ed ero incuriosito dalla sua formulazione.
Grazie mille.

*chiarisco quattro cifre separate da un punto, e queste cifre con un numero, o due o tre massimo, poiché include sia un 255.255.255.255 che, per esempio, i DNS di Google 8.8.8.8
rai
Imperturbabile Insigne
Imperturbabile Insigne
Messaggi: 2848
Iscrizione: domenica 11 maggio 2008, 18:03
Desktop: plasma
Distribuzione: 22.04
Località: Palermo

Re: Informazione su comando grep

Messaggio da rai »

Codice: Seleziona tutto

grep -E '\b[0-9]{1,3}(\.[0-9]{1,3}){3}'
Questa sintassi è più avanzata di quella che grep usa di base perché stai usando l'opzione -E che indica a grep che deve interpretare il pattern considerandolo una espressione regolare estesa. Si può andare oltre quando è necessario, usando l'opzione -P per sfruttare una sintassi più potente, Perl compatibile.

\b indica che tutto quello che segue nella regex matcha solo se nel testo ci si trova all'inizio di una parola

[0-9] è una classe di caratteri, in questo caso matcha qualsiasi cifra da 0 a 9; per es [a-zA-Z] corrisponderebbe a qualsiasi lettera minuscola o maiuscola
{1,3} è un quantificatore e stabilisce che l'elemento precedente matcha solo se è presente minimo 1 volta e massimo 3 volte
\ è il carattere di escape che modifica il significato del carattere seguente. In questo caso il carattere seguente è il . : il punto nelle regex è un metacarattere "jolly" che matcha qualsiasi carattere nel testo. Nel nostro caso invece noi vogliamo la corrispondenza proprio con un punto, letteralmente. Allora \. significa proprio questo, matcha solo se trova nel testo il carattere punto
Le parentesi tonde racchiudono un subpattern, questo subpattern lo vogliamo ripetuto esattemente 3 volte ( . . . ){3}
sarebbe stato equivalente ma meno leggibile scrivere:

Codice: Seleziona tutto

"\b[0-9]{1,3}\.0-9]{1,3}\.0-9]{1,3}\.0-9]{1,3}"
In questo forum passano esperti di grep, quindi se non sono stato chiaro chiedi e aspetta paziente che intervengano. Ti suggerisco comunque di studiare man grep e man pcrepattern mano a mano che ti imbatti in una cosa nuova nel campo delle regex
Simenon
Prode Principiante
Messaggi: 14
Iscrizione: venerdì 19 marzo 2021, 10:23
Desktop: Mint
Distribuzione: Mint
Sesso: Maschile
Località: Bologna

Re: Informazione su comando grep

Messaggio da Simenon »

rai ha scritto:
lunedì 25 aprile 2022, 20:30

Codice: Seleziona tutto

grep -E '\b[0-9]{1,3}(\.[0-9]{1,3}){3}'
Questa sintassi è più avanzata di quella che grep usa di base perché stai usando l'opzione -E che indica a grep che deve interpretare il pattern considerandolo una espressione regolare estesa. Si può andare oltre quando è necessario, usando l'opzione -P per sfruttare una sintassi più potente, Perl compatibile.

\b indica che tutto quello che segue nella regex matcha solo se nel testo ci si trova all'inizio di una parola

[0-9] è una classe di caratteri, in questo caso matcha qualsiasi cifra da 0 a 9; per es [a-zA-Z] corrisponderebbe a qualsiasi lettera minuscola o maiuscola
{1,3} è un quantificatore e stabilisce che l'elemento precedente matcha solo se è presente minimo 1 volta e massimo 3 volte
\ è il carattere di escape che modifica il significato del carattere seguente. In questo caso il carattere seguente è il . : il punto nelle regex è un metacarattere "jolly" che matcha qualsiasi carattere nel testo. Nel nostro caso invece noi vogliamo la corrispondenza proprio con un punto, letteralmente. Allora \. significa proprio questo, matcha solo se trova nel testo il carattere punto
Le parentesi tonde racchiudono un subpattern, questo subpattern lo vogliamo ripetuto esattemente 3 volte ( . . . ){3}
sarebbe stato equivalente ma meno leggibile scrivere:

Codice: Seleziona tutto

"\b[0-9]{1,3}\.0-9]{1,3}\.0-9]{1,3}\.0-9]{1,3}"
In questo forum passano esperti di grep, quindi se non sono stato chiaro chiedi e aspetta paziente che intervengano. Ti suggerisco comunque di studiare man grep e man pcrepattern mano a mano che ti imbatti in una cosa nuova nel campo delle regex
Grazie rai, adesso mi è un pochino più chiaro il tutto. Avevo usato anche io il

Codice: Seleziona tutto

man grep
ma senza troppi lumi.
Volevo chiederti un paio di cose: mi sono accorto di un "baco" di questo comando, e cioè che acriticamente mi va ad evidenziare quattro cifre da massimo tre numeri separate da tre punti. In questo modo va ad evidenziare anche indirizzi IP impossibili. Ho fatto questo esperimento con RegExr, allego la foto, indicando come impossibili gli ultimi due. C'è un modo per settare come indirizzo massimo il 255.255.255.255?

Immagine


Un'altra cosa: le espressioni regolari valgono con la stessa sintassi sia per bash che per perl che per python? Ho trovato alcuni corsi e documenti online, che specificano essere per Python o per Perl, ma se la sintassi rimane invariata anche per Bash potrei studiarmeli (scusa l'ignoranza della domanda...)
rai
Imperturbabile Insigne
Imperturbabile Insigne
Messaggi: 2848
Iscrizione: domenica 11 maggio 2008, 18:03
Desktop: plasma
Distribuzione: 22.04
Località: Palermo

Re: Informazione su comando grep

Messaggio da rai »

l'espressione più selettiva che chiedi potrebbe essere:

Codice: Seleziona tutto

'\b([0-2][0-5]{2}){1,3}(\.([0-2][0-5]{2}){1,3}){3}'
così corrispondono tutti gli indirizzi da 0.0.0.0 a 255.255.255.255

EDIT Non è vero, non funziona sempre. appena posso posto la sintassi corretta
Simenon
Prode Principiante
Messaggi: 14
Iscrizione: venerdì 19 marzo 2021, 10:23
Desktop: Mint
Distribuzione: Mint
Sesso: Maschile
Località: Bologna

Re: Informazione su comando grep

Messaggio da Simenon »

rai ha scritto:
martedì 26 aprile 2022, 10:48
l'espressione più selettiva che chiedi potrebbe essere:

Codice: Seleziona tutto

'\b([0-2][0-5]{2}){1,3}(\.([0-2][0-5]{2}){1,3}){3}'
così corrispondono tutti gli indirizzi da 0.0.0.0 a 255.255.255.255

EDIT Non è vero, non funziona sempre. appena posso posto la sintassi corretta
Grazie mille Rai, aspetto il tuo messaggio

PS: ho trovato questo https://it.wikipedia.org/wiki/%5Etxt2regex$ in pratica è un software che permette di formulare espressioni regolari a partire da delle domande. Lo conosci? Potrebbe essere interessante
rai
Imperturbabile Insigne
Imperturbabile Insigne
Messaggi: 2848
Iscrizione: domenica 11 maggio 2008, 18:03
Desktop: plasma
Distribuzione: 22.04
Località: Palermo

Re: Informazione su comando grep

Messaggio da rai »

Ecco questa dovrebbe funzionare in tutti i casi

Codice: Seleziona tutto

"(\b[0-9]{1,2}|1[0-9]{2}|2[0-4][0-9]|25[0-5])(\.([0-9]{1,2}|1[0-9]{2}|2[0-4][0-9]|25[0-5])){3}\b"
Non conoscevo il tool del tuo PS: interessante ma non ho avuto tempo per provarlo. Puoi farlo tu cercando di fargli costruire la regex precedente per matchare gli indirizzi IP
Avatar utente
crap0101
Rampante Reduce
Rampante Reduce
Messaggi: 8242
Iscrizione: martedì 30 ottobre 2007, 6:33
Desktop: LXDE
Distribuzione: Ubuntu 18.04.1 LTS
Sesso: Maschile
Località: TO
Contatti:

Re: Informazione su comando grep

Messaggio da crap0101 »

rai ha scritto:
martedì 26 aprile 2022, 23:10
Ecco questa dovrebbe funzionare in tutti i casi

Codice: Seleziona tutto

"(\b[0-9]{1,2}|1[0-9]{2}|2[0-4][0-9]|25[0-5])(\.([0-9]{1,2}|1[0-9]{2}|2[0-4][0-9]|25[0-5])){3}\b"
Non conoscevo il tool del tuo PS: interessante ma non ho avuto tempo per provarlo. Puoi farlo tu cercando di fargli costruire la regex precedente per matchare gli indirizzi IP
questa non è male ma mi pare matchare anche formati non proprio corretti come

Codice: Seleziona tutto

crap0101@orange:~$ echo 0.01.1.229 | grep -E "(\b[0-9]{1,2}|1[0-9]{2}|2[0-4][0-9]|25[0-5])(\.([0-9]{1,2}|1[0-9]{2}|2[0-4][0-9]|25[0-5])){3}\b"
0.01.1.229
Una versione che dovrebbe andare bene è

Codice: Seleziona tutto

"^([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])\.([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])\.([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])\.([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])$"
usando le extended... lunga e non il massimo della leggibilità (ed evitando di usare backreference che potrebbero dare problemi). Con -P si riesce a fare sicuramente qualcosa di meglio (e corto)

Poi se si ha tempo di verificare qualche miliardo di indirizzi...

Codice: Seleziona tutto

crap0101@orange:~/test$ cat test_ip_address.py
import itertools as it
import re
import sys

# extended re for IPv4 adresses
regex = "^([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])\.([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])\.([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])\.([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])$"

def test (max_it):
    for i, comb in enumerate(it.combinations(range(256), 4)):
        address = '.'.join(map(str, comb))
        assert re.match(regex, address), "Err: {}".format(address)
        #print (address)
        if i > max_it:
            break

if __name__ == '__main__':
    max_it = float('+inf')
    if sys.argv[1:]:
        max_it = int(sys.argv[1])
    try:
        test(max_it)
    except KeyboardInterrupt:
        print("...too long :-)")
:-D
http://www.gnu.org/ http://boinc.berkeley.edu/ http://www.python-it.org/
- Ricorda le ultime parole di suo padre: «Sta' alla larga dalle chiese, figlio. La sola cosa per cui hanno la chiave è il merdaio. E giurami che non porterai mai un distintivo della legge» - W.S. Burroughs
Scrivi risposta

Ritorna a “Programmazione”

Chi c’è in linea

Visualizzano questa sezione: maidasette e 9 ospiti