Restituisce solo la parte di una linea dopo un modello corrispondente


109

Quindi, aprire un file con cate quindi utilizzare grepper ottenere le linee corrispondenti mi porta così lontano solo quando sto lavorando con il set di log specifico con cui ho a che fare. Ha bisogno di un modo per abbinare le linee a un modello, ma solo per restituire la parte della linea dopo la corrispondenza. La parte prima e dopo la partita varierà costantemente. Ho giocato usando sedo awk, ma non sono stato in grado di capire come filtrare la linea per eliminare la parte prima della partita, o semplicemente restituire la parte dopo la partita, funzionerà. Questo è un esempio di una linea che devo filtrare:

2011-11-07T05:37:43-08:00 <0.4> isi-udb5-ash4-1(id1) /boot/kernel.amd64/kernel: [gmp_info.c:1758](pid 40370="kt: gmp-drive-updat")(tid=100872) new group: <15,1773>: { 1:0-25,27-34,37-38, 2:0-33,35-36, 3:0-35, 4:0-9,11-14,16-32,34-38, 5:0-35, 6:0-15,17-36, 7:0-16,18-36, 8:0-14,16-32,34-36, 9:0-10,12-36, 10-11:0-35, 12:0-5,7-30,32-35, 13-19:0-35, 20:0,2-35, down: 8:15, soft_failed: 1:27, 8:15, stalled: 12:6,31, 20:1 }

La parte di cui ho bisogno è tutto dopo "bloccato".

Lo sfondo dietro questo è che posso scoprire quanto spesso qualcosa si blocca:

cat messages | grep stalled | wc -l

Quello che devo fare è scoprire quante volte un certo nodo si è bloccato (indicato dalla porzione prima di ogni due punti dopo "bloccato". Se avessi solo grep per quello (cioè 20 :) potrebbe restituire linee che hanno errori soft, ma nessuna bancarella, il che non mi aiuta. Devo filtrare solo la parte bloccata in modo da poter quindi grep per un nodo specifico tra quelli bloccati.

A tutti gli effetti, questo è un sistema freebsd con utility GNU standard, ma non posso installare nulla in più per aiutare.


@Gilles, strano come non sia apparso quando ho cercato, anche se non ho usato il titolo con cui alla fine sono andato ... ma non è stato visualizzato nella schermata sotto il mio titolo. Ad ogni modo, a parte questo, ciò potrebbe portarmi dove voglio, anche se ho bisogno dell'intera riga dopo la partita, non della prima parola, ma potrebbe non cambiare molto.
MaQleod,

Il suo titolo ha fatto schifo. Ho rubato il tuo, il che è molto bello. Prendi la sedsoluzione e non trattare gli spazi bianchi in modo speciale.
Gilles,

@Gilles, è qualcosa che non sono del tutto sicuro di come fare. Sto ancora imparando sed.
MaQleod,


1
@ shaa0601 Non capisco la tua domanda, è particolarmente difficile da seguire in un commento senza formattazione. Fai una nuova domanda autonoma.
Gilles,

Risposte:


141

Lo strumento canonico per questo sarebbe sed.

sed -n -e 's/^.*stalled: //p'

Spiegazione dettagliata:

  • -n significa non stampare nulla per impostazione predefinita.
  • -e è seguito da un comando sed.
  • s è il comando di sostituzione del modello.
  • L'espressione regolare ^.*stalled:corrisponde al modello che stai cercando, più qualsiasi testo precedente ( .*ovvero qualsiasi testo, con un iniziale ^per dire che la corrispondenza inizia all'inizio della riga). Si noti che se si stalled:verifica più volte sulla riga, corrisponderà all'ultima occorrenza.
  • La corrispondenza, ovvero tutto sulla riga fino a stalled:, viene sostituita dalla stringa vuota (ovvero eliminata).
  • L'ultimo psignifica stampare la linea trasformata.

Se si desidera conservare la parte corrispondente, utilizzare un backreference: \1nella parte sostitutiva designa ciò che è all'interno di un gruppo \(…\)nel modello. Qui, è possibile scrivere stalled:nuovamente nella parte di sostituzione; questa funzione è utile quando il motivo che stai cercando è più generale di una semplice stringa.

sed -n -e 's/^.*\(stalled: \)/\1/p'

A volte ti consigliamo di rimuovere la parte della linea dopo la partita. Puoi includerlo nella corrispondenza includendo .*$alla fine del modello (qualsiasi testo .*seguito dalla fine della riga $). A meno che non si inserisca quella parte in un gruppo a cui si fa riferimento nel testo sostitutivo, la fine della riga non sarà nell'output.

Come ulteriore illustrazione di gruppi e riferimenti secondari, questo comando scambia la parte prima della corrispondenza e la parte dopo la corrispondenza.

sed -n -e 's/^\(.*\)\(stalled: \)\(.*\)$/\3\2\1/p'

Ho provato i primi due esempi e sembra appendere. Non ricevo un messaggio di errore, né ricevo un nuovo prompt, proprio niente.
MaQleod,

2
@MaQleod Oh, è in attesa di input su input standard, che qui è il terminale perché non lo hai reindirizzato. Qui eseguiresti un reindirizzamento di input sed … <messages, poiché desideri elaborare i dati da un file. Per agire sui dati prodotti da un altro comando, devi usare un tubo: somecommand | sed ….
Gilles,

1
a destra, blackout di fine giornata lì. il comando funziona perfettamente, grazie.
MaQleod,

1
La migliore spiegazione di sed che ho visto finora - grazie!
Jon Wadsworth,

1
@ungalcrys Versione più breve di cosa? Questo non equivale a nessuno dei comandi nella mia risposta. Consiglierei di scriverlo sed 's/^.*stalled//'perché -rè specifico per Linux e non funziona su altri sistemi come macOS e qui non ne trarrai alcun vantaggio.
Gilles,

72

L'altro strumento canonico che già usi grep::

Per esempio:

grep -o 'stalled.*'

Ha lo stesso risultato della seconda opzione di Gilles:

sed -n -e 's/^.*\(stalled: \)/\1/p'

La -obandiera restituisce la --only-matchingparte dell'espressione, quindi non l'intera linea che, ovviamente, è normalmente eseguita da grep.

Per rimuovere "stalled:" dall'output, possiamo usare un terzo strumento canonico, tagliare:

grep -o 'stalled.*' | cut -f2- -d:

Il cutcomando usa delimitatore :e stampa il campo 2 fino alla fine. Naturalmente è una questione di preferenza, ma la cutsintassi che trovo molto facile da ricordare.


1
Grazie per aver menzionato l' -oopzione! Volevo sottolineare che grepnon riconosce il \ncome una nuova riga, quindi il tuo primo esempio corrisponde solo al primo npersonaggio. Ad esempio, echo "Hello Anne" | grep -o 'A[^\n]*'restituisce la stringa A. Tuttavia, echo "Hello Anne" | grep -o 'A.*'restituisce il previsto Anne, poiché .corrisponde a qualsiasi carattere tranne la nuova riga.
adamlamar,

1
Si noti che le virgolette attorno al cutdelimitatore -d':'vengono rimosse da @poige. Trovo più facile da ricordare tra virgolette, ad esempio con -d' 'o -d';'.
Anne van Rossum,

Secondo la tua scoperta, dovrebbe essere più facile ricordare di usare anche le virgolette -f 2. Scherzi a parte, perché no?
poige,

Perché un delimitatore come un punto e virgola ;anziché un colon :verrà interpretato in modo diverso se non citato. Naturalmente questo è un comportamento logico, ma mi piace ancora fare affidamento sulla memoria muscolare. Non mi piace citare il delimitatore una volta ma non l'altra volta. Solo preferenze personali, come ho detto prima: più facili da ricordare.
Anne van Rossum,

il periodo che fa parte del periodo .*necessario, ha funzionato bene per me: cat filename | grep 'Return only this line xyz text' | grep -o 'xyz.*' ritornaxyz text
ron

4

Prima ifconfig | grep eth0 | cut -f3- -d:lo prendevo

    [root@MyPC ~]# ifconfig
    eth0  Link encap:Ethernet  HWaddr AC:B4:CA:DD:E6:F8
          inet addr:192.168.0.2  Bcast:192.168.0.255  Mask:255.255.255.0
          UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
          RX packets:78998810244 errors:1 dropped:0 overruns:0 frame:1
          TX packets:20113430261 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:1000
          RX bytes:110947036025418 (100.9 TiB)  TX bytes:15010653222322 (13.6 TiB)

e farlo sembrare così

    [root@MyPC ~]# ifconfig | grep eth0 | cut -f3- -d:
    C4:7A:4D:F6:B8

2
Questo risponde alla domanda?
Stephen Rauch,

1
È possibile utilizzare cat /sys/class/net/*/address, nessuna analisi richiesta.
Anne van Rossum,

1

Ancora un altro strumento canonico che hai considerato awkpotrebbe essere usato con la seguente riga:

awk -F"stalled" '/stalled/{print $2}' messages

Spiegazione dettagliata:

  • -Fdefinisce un separatore per la linea, ovvero "bloccato". Tutto prima del separatore viene affrontato $1e tutto dopo $2.
  • /reg-ex/ Cerca l'espressione regolare corrispondente, in questo caso "bloccata".
  • {print $<n>}- stampa n colonna. Poiché il separatore è definito come bloccato, tutto ciò che segue è considerato la seconda colonna.
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.