Buon modo
Normalmente non puoi farlo con grep ma puoi usare altri strumenti. AWK è già stato menzionato ma puoi anche usare sed
, in questo modo:
sed -e '1p' -e '/youpattern/!d'
Come funziona:
L'utilità Sed funziona su ciascuna riga singolarmente, eseguendo i comandi specificati su ciascuna di esse. Puoi avere più comandi, specificando diverse -e
opzioni. Possiamo anteporre ogni comando con un parametro range che specifica se questo comando deve essere applicato o meno a una riga specifica.
"1p" è un primo comando. Usa un p
comando che normalmente stampa tutte le linee. Ma lo anteponiamo con un valore numerico che specifica l'intervallo a cui dovrebbe essere applicato. Qui, usiamo 1
che significa prima linea. Se si desidera stampare più linee, è possibile utilizzare x,yp
dove x
è la prima linea per la stampa, y
è ultima riga da stampare. Ad esempio, per stampare le prime 3 righe, si utilizzerà1,3p
Il comando successivo è d
che normalmente elimina tutte le righe dal buffer. Prima di questo comando mettiamo yourpattern
tra due /
personaggi. Questo è l'altro modo (in primo luogo era di specificare quali linee come abbiamo fatto con il p
comando) di indirizzare le linee su cui il comando dovrebbe essere in esecuzione. Ciò significa che il comando funzionerà solo per le linee corrispondenti yourpattern
. Tranne, usiamo il !
carattere prima del d
comando che inverte la sua logica. Quindi ora rimuoverà tutte le linee che non corrispondono al modello specificato.
Alla fine, sed stamperà tutte le righe rimaste nel buffer. Ma abbiamo rimosso le linee che non corrispondono dal buffer, quindi verranno stampate solo le linee corrispondenti.
Per riassumere: stampiamo la prima riga, quindi eliminiamo dall'input tutte le righe che non corrispondono al nostro modello. Resto delle linee vengono stampati (in modo che solo le linee che fanno corrispondere al modello).
Problema di prima linea
Come menzionato nei commenti, c'è un problema con questo approccio. Se il motivo specificato corrisponde anche alla prima riga, verrà stampato due volte (una volta per p
comando e una volta a causa di una corrispondenza). Possiamo evitarlo in due modi:
Aggiunta del 1d
comando dopo 1p
. Come ho già accennato, il d
comando elimina le righe dal buffer e specifichiamo che è intervallo per il numero 1, il che significa che eliminerà solo la 1a riga. Quindi il comando sarebbesed -e '1p' -e '1d' -e '/youpattern/!d'
Usando il 1b
comando, invece di 1p
. È un trucco. b
Il comando ci consente di passare ad altri comandi specificati da un'etichetta (in questo modo alcuni comandi possono essere omessi). Ma se questa etichetta non viene specificata (come nel nostro esempio) passa alla fine dei comandi, ignorando il resto dei comandi per la nostra linea. Quindi, nel nostro caso, l'ultimo d
comando non rimuoverà questa riga dal buffer.
Esempio completo:
ps aux | sed -e '1b' -e '/syslog/!d'
Usando il punto e virgola
Alcune sed
implementazioni possono farti risparmiare un po 'di battitura utilizzando il punto e virgola per separare i comandi anziché utilizzare più -e
opzioni. Quindi se non ti interessa essere portatile il comando sarebbe ps aux | sed '1b;/syslog/!d'
. Funziona almeno in GNU sed
e busybox
implementazioni.
Modo folle
Ecco, tuttavia, un modo piuttosto folle per farlo con grep. Non è sicuramente ottimale, sto pubblicando questo solo a scopo di apprendimento, ma potresti usarlo ad esempio, se non hai altri strumenti nel tuo sistema:
ps aux | grep -n '.*' | grep -e '\(^1:\)\|syslog'
Come funziona
Innanzitutto, utilizziamo l' -n
opzione per aggiungere i numeri di riga prima di ogni riga. Vogliamo numerare tutte le linee che stiamo abbinando .*
- qualsiasi cosa, anche una linea vuota. Come suggerito nei commenti, possiamo anche abbinare '^', il risultato è lo stesso.
Quindi stiamo usando espressioni regolari estese in modo da poter usare \|
caratteri speciali che funzionano come OR. Quindi abbiniamo se la linea inizia con 1:
(prima riga) o contiene il nostro modello (in questo caso è syslog
).
Problema con i numeri di riga
Ora il problema è che stiamo ottenendo questi brutti numeri di riga nel nostro output. Se questo è un problema, possiamo rimuoverli con cut
, in questo modo:
ps aux | grep -n '.*' | grep -e '\(^1:\)\|syslog' | cut -d ':' -f2-
-d
L'opzione specifica il delimitatore, -f
specifica i campi (o colonne) che vogliamo stampare. Quindi vogliamo tagliare ogni riga su ogni :
carattere e stampare solo la 2a e tutte le colonne successive. Questo rimuove efficacemente la prima colonna con il suo delimitatore ed è esattamente ciò di cui abbiamo bisogno.
ack
sono così utili, e perché ilperl
passato è salito alle stellesed
,awk
ecc. In popolarità: è importante che le parti si riassumano in un insieme coerente.