GNU/Linux >> Linux Esercitazione >  >> Linux

Manipolazione del testo dalla riga di comando con grep

Immagina di avere un file (o un gruppo di file) e di voler cercare una stringa specifica o un'impostazione di configurazione all'interno di questi file. Aprire ogni file individualmente e cercare di trovare la stringa specifica sarebbe noioso e probabilmente non è l'approccio giusto. Allora cosa possiamo usare?

Ci sono molti strumenti che possiamo usare nei sistemi basati su *nix per trovare e manipolare il testo. In questo articolo tratteremo il grep comando per cercare i pattern, trovati nei file o provenienti da uno stream (un file o input proveniente da una pipe, o | ). In un prossimo articolo, vedremo anche come utilizzare sed (Stream Editor) per manipolare uno stream.

Il modo migliore per comprendere il funzionamento di un programma o di un'utilità è consultare la relativa pagina man. Molti (se non tutti) strumenti Unix forniscono pagine di manuale durante l'installazione. Sui sistemi basati su Red Hat Enterprise Linux, possiamo eseguire quanto segue per elencare grep i file di documentazione di:

$ rpm -qd grep
/usr/share/doc/grep/AUTHORS
/usr/share/doc/grep/NEWS
/usr/share/doc/grep/README
/usr/share/doc/grep/THANKS
/usr/share/doc/grep/TODO
/usr/share/info/grep.info.gz
/usr/share/man/man1/egrep.1.gz
/usr/share/man/man1/fgrep.1.gz

Con le pagine man a nostra disposizione, ora possiamo usare grep ed esplora le sue opzioni.

grep basi

Durante questa parte dell'articolo, utilizziamo le words file, che puoi trovare al seguente percorso:

$ ls -l /usr/share/dict/words 
lrwxrwxrwx. 1 root root 11 Feb  3  2019 /usr/share/dict/words -> linux.words

Questo file contiene 479.826 parole ed è fornito dalle words pacchetto. Nel mio sistema Fedora, quel pacchetto è words-3.0-33.fc30.noarch . Quando elenchiamo il contenuto delle words file, vediamo il seguente output:

$ cat /usr/share/dict/words
1080
10-point
10th
11-point
[……]
[……] 
zyzzyva
zyzzyvas
ZZ
Zz
zZt
ZZZ

Ok, quindi abbiamo detto le words il file conteneva 479.826 righe, ma come facciamo a saperlo? Ricorda, abbiamo parlato delle pagine man in precedenza. Vediamo se grep offre un'opzione per contare le righe in un determinato file.

Ironia della sorte, useremo grep per cercare l'opzione come segue:

Quindi, abbiamo ovviamente bisogno di -c o l'opzione lunga --count , per contare il numero di righe in un determinato file. Conteggio delle righe in /usr/share/dict/words rendimenti:

$ grep -c '.' /usr/share/dict/words 
479826

Il '.' significa che conteremo tutte le righe contenenti almeno un carattere, spazio, spazio vuoto, tabulazione, ecc.

grep di base espressioni regolari

Il grep il comando diventa più potente quando utilizziamo espressioni regolari (regex). Quindi, mentre ci concentriamo su grep comando stesso, tratteremo anche la sintassi di base delle espressioni regolari.

Supponiamo di essere interessati solo alle parole che iniziano con Z . Questa è la situazione in cui le espressioni regolari tornano utili. Usiamo il carato (^ ) per cercare pattern che iniziano con un carattere specifico, che denota l'inizio di una stringa:

Per cercare pattern che terminano con un carattere specifico, utilizziamo il simbolo del dollaro ($ ) per indicare la fine della stringa. Vedi l'esempio qui sotto dove cerchiamo le stringhe che terminano con hat :

Per stampare tutte le righe che contengono hat indipendentemente dalla sua posizione, sia all'inizio che alla fine della riga, useremmo qualcosa del tipo:

Il ^ e $ sono chiamati metacaratteri e devono essere sottoposti a escape con una barra rovesciata (\ ) quando vogliamo abbinare questi caratteri alla lettera. Se vuoi saperne di più sui metacaratteri, visita https://www.regular-expressions.info/characters.html.

Esempio:rimuovi commenti

Ora che abbiamo graffiato la superficie di grep , lavoriamo su alcuni scenari del mondo reale. Molti file di configurazione in *nix contengono commenti che descrivono diverse impostazioni all'interno del file di configurazione. Il /etc/fstab , ad esempio, il file ha:

$ cat /etc/fstab 

#
# /etc/fstab
# Created by anaconda on Thu Oct 27 05:06:06 2016
#
# Accessible filesystems, by reference, are maintained under '/dev/disk'
# See man pages fstab(5), findfs(8), mount(8) and/or blkid(8) for more info
#
/dev/mapper/VGCRYPTO-ROOT /                       ext4    defaults,x-systemd.device-timeout=0 1 1
UUID=e9de0f73-ddddd-4d45-a9ba-1ffffa /boot                   ext4    defaults        1 2
LABEL=SSD_SWAP		swap		swap		defaults	0 0
#/dev/mapper/VGCRYPTO-SWAP swap                    swap    defaults,x-systemd.device-timeout=0 0 0

I commenti sono contrassegnati dall'hash (# ), e vogliamo ignorarli quando vengono stampati. Un'opzione è il cat comando:

$ cat /etc/fstab | grep -v '^#' 

Tuttavia, non hai bisogno di cat qui (evitare l'uso inutile del gatto). Il grep command è perfettamente in grado di leggere file, quindi puoi usare qualcosa del genere per ignorare le righe che contengono commenti:

$ grep -v '^#' /etc/fstab 

Se invece vuoi inviare l'output (senza commenti) a un altro file, dovresti usare:

$ grep -v '^#' /etc/fstab > ~/fstab_without_comment

Mentre grep può formattare l'output sullo schermo, questo comando non è in grado di modificare un file sul posto. Per fare ciò, avremmo bisogno di un editor di file come ed . Nel prossimo articolo useremo sed per ottenere la stessa cosa che abbiamo fatto qui con grep .

Esempio:rimuovere commenti e righe vuote

Mentre siamo ancora su grep , esaminiamo il /etc/sudoers file. Questo file contiene molti commenti, ma siamo interessati solo alle righe che non hanno commenti e vogliamo anche eliminare le righe vuote.

Quindi, per prima cosa, rimuoviamo le righe che contengono i commenti. Viene prodotto il seguente output:

# grep -v '^#' /etc/sudoers 

Defaults   !visiblepw

Defaults    env_reset
Defaults    env_keep =  "COLORS DISPLAY HOSTNAME HISTSIZE KDEDIR LS_COLORS"
Defaults    env_keep += "MAIL PS1 PS2 QTDIR USERNAME LANG LC_ADDRESS LC_CTYPE"
Defaults    env_keep += "LC_COLLATE LC_IDENTIFICATION LC_MEASUREMENT LC_MESSAGES"
Defaults    env_keep += "LC_MONETARY LC_NAME LC_NUMERIC LC_PAPER LC_TELEPHONE"
Defaults    env_keep += "LC_TIME LC_ALL LANGUAGE LINGUAS _XKB_CHARSET XAUTHORITY"
Defaults    secure_path = /usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
root	ALL=(ALL) 	ALL
%wheel	ALL=(ALL)	ALL

Ora, vogliamo sbarazzarci delle righe vuote (vuote). Bene, è facile, esegui un altro grep comando:

# grep -v '^#' /etc/sudoers | grep -v '^$' 
Defaults   !visiblepw
Defaults    env_reset
Defaults    env_keep =  "COLORS DISPLAY HOSTNAME HISTSIZE KDEDIR LS_COLORS"
Defaults    env_keep += "MAIL PS1 PS2 QTDIR USERNAME LANG LC_ADDRESS LC_CTYPE"
Defaults    env_keep += "LC_COLLATE LC_IDENTIFICATION LC_MEASUREMENT LC_MESSAGES"
Defaults    env_keep += "LC_MONETARY LC_NAME LC_NUMERIC LC_PAPER LC_TELEPHONE"
Defaults    env_keep += "LC_TIME LC_ALL LANGUAGE LINGUAS _XKB_CHARSET XAUTHORITY"
Defaults    secure_path = /usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
root	ALL=(ALL) 	ALL
%wheel	ALL=(ALL)	ALL
valentin.local	ALL=NOPASSWD: /usr/bin/updatedb

Potremmo fare di meglio? Possiamo eseguire il nostro grep comando per essere più rispettoso delle risorse e non fork grep due volte? Possiamo certamente:

# grep -Ev '^#|^$' /etc/sudoers 
Defaults   !visiblepw
Defaults    env_reset
Defaults    env_keep =  "COLORS DISPLAY HOSTNAME HISTSIZE KDEDIR LS_COLORS"
Defaults    env_keep += "MAIL PS1 PS2 QTDIR USERNAME LANG LC_ADDRESS LC_CTYPE"
Defaults    env_keep += "LC_COLLATE LC_IDENTIFICATION LC_MEASUREMENT LC_MESSAGES"
Defaults    env_keep += "LC_MONETARY LC_NAME LC_NUMERIC LC_PAPER LC_TELEPHONE"
Defaults    env_keep += "LC_TIME LC_ALL LANGUAGE LINGUAS _XKB_CHARSET XAUTHORITY"
Defaults    secure_path = /usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
root	ALL=(ALL) 	ALL
%wheel	ALL=(ALL)	ALL
valentin.local	ALL=NOPASSWD: /usr/bin/updatedb

Qui abbiamo introdotto un altro grep opzione, -E (o --extended-regexp ) <PATTERN> è un'espressione regolare estesa.

Esempio:stampa solo /etc/passwd utenti

È ovvio che grep è potente se usato con le espressioni regolari. Questo articolo copre solo una piccola parte di ciò che grep ne è davvero capace. Per dimostrare le capacità di grep e l'uso di espressioni regolari, analizzeremo il /etc/passwd archiviare e stampare solo i nomi utente.

Il formato del /etc/passwd il file è il seguente:

$ head /etc/passwd
root:x:0:0:root:/root:/bin/bash
bin:x:1:1:bin:/bin:/sbin/nologin
daemon:x:2:2:daemon:/sbin:/sbin/nologin
adm:x:3:4:adm:/var/adm:/sbin/nologin
lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin
sync:x:5:0:sync:/sbin:/bin/sync
shutdown:x:6:0:shutdown:/sbin:/sbin/shutdown
halt:x:7:0:halt:/sbin:/sbin/halt
mail:x:8:12:mail:/var/spool/mail:/sbin/nologin
operator:x:11:0:operator:/root:/sbin/nologin

I campi sopra indicati hanno il seguente significato:

<name>:<password>:<UID>:<GID>:<GECOS>:<directory>:<shell>

Vedi man 5 passwd per ulteriori informazioni su /etc/passwd file. Per stampare solo i nomi utente, potremmo usare qualcosa di simile al seguente:

$ grep -Eo '^[a-zA-Z_-]+' /etc/passwd
root
bin
daemon
adm
lp
sync
shutdown
halt
mail
operator

In grep sopra comando, abbiamo introdotto un'altra opzione:-o (o --only-matching ) per mostrare solo la parte di riga corrispondente a <PATTERN> . Quindi, abbiamo combinato -Eo per ottenere il risultato desiderato.

Ora spezzeremo il comando sopra in modo da poter capire meglio cosa sta realmente accadendo. Da sinistra a destra:

  • ^ partite all'inizio della riga.
  • [a-zA-Z_-] è chiamata classe di caratteri e corrisponde a un elenco incluso di corrispondenza di caratteri singoli.
  • + è un quantificatore che corrisponde tra uno e un numero illimitato di volte.

L'espressione regolare sopra si ripeterà fino a raggiungere un carattere che non corrisponde. La prima riga del file è:

root:x:0:0:root:/root:/bin/bash

Viene elaborato come segue:

  1. Il primo carattere è un r , quindi è abbinato a [a-z] .
  2. Il + passa al carattere successivo.
  3. Il secondo carattere è un o e questo è abbinato a [a-z] .
  4. Il + passa al carattere successivo.

Questa sequenza si ripete finché non premiamo i due punti (: ). La classe di caratteri [a-zA-Z_-] non corrisponde a : simbolo, quindi grep passa alla riga successiva.

Poiché i nomi utente nel passwd sono tutti minuscoli, potremmo anche semplificare la nostra classe di caratteri come segue e ottenere comunque il risultato desiderato:

$ grep -Eo '^[a-z_-]+' /etc/passwd

Esempio:trova un processo

Quando si utilizza ps per grep per un processo, usiamo spesso qualcosa come:

$ ps aux | grep ‘thunderbird’

Ma il ps il comando non elencherà solo il thunderbird processi. Elenca anche il grep comando che abbiamo appena eseguito, poiché grep è anche in esecuzione dopo la pipe ed è mostrato nell'elenco dei processi:

$ ps aux | grep thunderbird
val+  2196  0.7  2.1 52 33 tty2  Sl+ 16:47  1:55 /usr/lib64/thunderbird/thunderbird
val+ 14064  0.0  0.0 57 82 pts/2  S+   21:12   0:00 grep --color=auto thunderbird

Possiamo gestirlo aggiungendo grep -v grep per escludere grep dall'output:

$ ps aux | grep thunderbird | grep -v grep
val+  2196  0.7  2.1 52 33 tty2  Sl+ 16:47  1:55 /usr/lib64/thunderbird/thunderbird

Durante l'utilizzo di grep -v grep farà quello che volevamo, esistono modi migliori per ottenere lo stesso risultato senza biforcare un nuovo grep processo:

$ ps aux | grep [t]hunderbird 
val+  2196  0.7  2.1 52 33 tty2  Sl+ 16:47  1:55 /usr/lib64/thunderbird/thunderbird

Il [t]hunderbird qui corrisponde al letterale t e fa distinzione tra maiuscole e minuscole. Non corrisponderà a grep , ed è per questo che ora vediamo solo thunderbird nell'output.

Questo esempio è solo una dimostrazione della flessibilità di grep cioè, non ti aiuterà a risolvere il tuo albero dei processi. Ci sono strumenti migliori adatti a questo scopo, come pgrep .

Concludi

Usa grep quando si desidera cercare un modello, in un file o in più directory in modo ricorsivo. Cerca di capire come funzionano le espressioni regolari quando grep , poiché le espressioni regolari possono essere potenti.

[Vuoi provare Red Hat Enterprise Linux? Scaricalo ora gratuitamente.]


Linux
  1. Ordina con l'ordinamento dalla riga di comando

  2. Lavorare con i flussi di dati sulla riga di comando di Linux

  3. Lavorare con le pipe sulla riga di comando di Linux

  4. Manipolazione del testo da riga di comando con sed

  5. Manipolare il tasto X e il puntatore sulla riga di comando?

Come utilizzare Nano, l'editor di testo della riga di comando di Linux

Utilizzo del comando GREP in Linux con esempi

Padroneggia la riga di comando di Linux

Il tutorial sul comando Grep con esempi per principianti

Manipolazione del testo con sed e grep

Tracciare il tempo con Timewarrior alla riga di comando