Limitare l'output grep alle linee brevi


8

Uso spesso grep per trovare file con una determinata voce come questa:

grep -R 'MyClassName'

La cosa buona è che restituisce i file, i loro contenuti e segna la stringa trovata in rosso. La cosa brutta è che ho anche enormi file in cui l'intero testo è scritto in un'unica grande riga. Ora grep emette troppo quando trova testo all'interno di quei file di grandi dimensioni. Esiste un modo per limitare l'output, ad esempio, a 5 parole a sinistra ea destra? O forse limitare l'output a 30 lettere a sinistra ea destra?


3
cut
Inoltra i

Quindi, supponiamo che lo schema che stai cercando sia in posizione 50, ma hai detto che vuoi solo 30 lettere. Che cosa vuoi fare allora? Ignora quella linea o includila anche nell'output ma tagliala? Cosa vuoi limitare esattamente: la ricerca o le linee stesse?
Sergiy Kolodyazhnyy

1
@Rinzwind Non capisco bene cosa vuoi ottenere cut, poiché si divide solo dal delimitatore o dal conteggio dei personaggi. Tuttavia, quando trovo una linea con MyClassNameessa può essere ovunque nella linea e non sempre nella stessa posizione. Inoltre, potrebbe esserci una variazione di caratteri nella parte anteriore e posteriore, che rompe la possibilità di dividere per delimitatore.
Socrate,

1
@SergiyKolodyazhnyy Quando MyClassNameè stata trovata una linea positiva con , voglio ottenere come risultato il nome del file e i caratteri x a sinistra ea destra. x è qualsiasi numero fornito, ad esempio 30. Il resto del contenuto del file deve essere ignorato. Questo per ottenere un contesto per i file corrispondenti e limitare il sovraccarico.
Socrate,

1
@Rinzwind Con quale tipo di delimitatore personalizzato suggeriresti cutse ci sono tre file con il seguente input: oiadfaosuoianavMyClassNameionaernaldfajde /(/&%%§%/(§(/MyClassName&((/$/$/(§/$&e public class MyClassName { public static void main(String[] args) { } }?
Socrate,

Risposte:


15

grepstesso ha solo opzioni per il contesto basato su linee. Un'alternativa è suggerita da questo post SU :

Una soluzione alternativa è abilitare l'opzione 'solo-matching' e quindi utilizzare la potenza di RegExp per grep un po 'più del tuo testo:

grep -o ".\{0,50\}WHAT_I_M_SEARCHING.\{0,50\}" ./filepath

Naturalmente, se utilizzi l'evidenziazione del colore, puoi sempre ripetere il grep per colorare solo la corrispondenza reale:

grep -o ".\{0,50\}WHAT_I_M_SEARCHING.\{0,50\}"  ./filepath | grep "WHAT_I_M_SEARCHING"

Come altra alternativa, suggerirei di foldinserire il testo e di inserirlo, ad esempio:

fold -sw 80 input.txt | grep ...

L' -sopzione farà foldspingere le parole alla riga successiva invece di interromperle.

Oppure usa un altro modo per dividere l'input in righe in base alla struttura dell'input. (Il post SU, ad esempio, si occupava di JSON, quindi usare jqecc. Per stampare piuttosto e grep... o semplicemente usare jqper fare il filtro da solo ... sarebbe meglio di una delle due alternative sopra indicate.)


Questo metodo GNU awk potrebbe essere più veloce:

gawk -v n=50 -v RS='MyClassName' '
  FNR > 1 { printf "%s: %s\n",FILENAME, p prt substr($0, 0, n)}
  {p = substr($0, length - n); prt = RT}
' input.txt
  • Di 'a awk di dividere i record sul modello che ci interessa ( -v RS=...) e il numero di caratteri nel contesto ( -v n=...)
  • Ogni record dopo il primo record ( FNR > 1) è uno in cui awk ha trovato una corrispondenza per il modello.
  • Quindi stampiamo ni caratteri finali della riga precedente ( p) e i ncaratteri iniziali della riga corrente ( substr($0, 0, n)), insieme al testo corrispondente per la riga precedente (che è prt)
    • impostiamo pe prt dopo la stampa, quindi il valore impostato viene utilizzato dalla riga successiva
    • RT è un GNUismo, ecco perché questo è specifico per GNU awk.

Per la ricerca ricorsiva, forse:

find . -type f -exec gawk -v n=50 -v RS='MyClassName' 'FNR>1{printf "%s: %s\n",FILENAME, p prt substr($0, 0, n)} {p = substr($0, length-n); prt = RT}' {} +

2
Ok funziona Sembra che Regex sia un approccio valido, quindi grazie per quello. Il tempo di elaborazione è piuttosto grande. Senza Regex come nel mio post sopra ci vogliono 4.912s e con Regex come nel tuo post ci vogliono 3m39.312s.
Socrate,

1
@Socrates vede se il metodo awk che ho aggiunto sopra funziona meglio
muru,

1
Il foldmetodo può essere utilizzato solo se sei sicuro che la stringa cercata non appare al bordo, altrimenti verrebbe nascosta da grep.
Melebio

1
@muru Grazie per il tuo suggerimento con gawk. Sfortunatamente, il comando suggerito findproduce output casuali e nessun nome di file, quando eseguito sul mio sistema. Inoltre, non sono abbastanza fluente awkper analizzare correttamente il comando. Attualmente, Regex in combinazione con greprisolve la questione forse non velocemente, ma affidabile. Ancora grazie mille.
Socrate,

1
@Socrate Penso di essere riuscito a correggere il comando awk. Il mio modello mentale era sbagliato su quale linea RTe prefisso, ecc. Dovevano essere usati.
muru,

1

L'uso della sola corrispondenza in combinazione con alcune altre opzioni (vedi sotto), potrebbe essere molto vicino a quello che stai cercando, senza il sovraccarico di elaborazione di regex menzionato nell'altra risposta

grep -RnHo 'MyClassName'
  • n output numerico, mostra il numero di riga della corrispondenza
  • H nome file, mostra il nome file all'inizio della riga della corrispondenza
  • o corrisponde solo, mostra solo la stringa matematica, non l'intera riga

Mentre è vero che il risultato viene trovato molto più velocemente, mancano informazioni. Viene visualizzato il percorso del file, viene mostrato il numero di riga, ma l'output del testo è solo la mia ricerca iniziale MyClassName. Quindi, il contesto è mancante.
Socrate,

grep -RnHo "MyClassName"e grep -Rno "MyClassName"hanno lo stesso output.
Socrate,

L'output di @Socrates non è lo stesso senza H nella stessa directory
Robert Riedl,

La -obandiera potrebbe essere interessante se la regex avesse una parte variabile. Per una stringa fissa, è inutile stamparla ogni volta. Molto probabilmente l'OP è interessato al prossimo contesto.
Melebio

1
@Socrate, vero - manca il contesto, ma ho pensato che fosse questo il punto? Limitare l'uscita? È possibile aggiungere nuovamente il contesto aggiungendo le righe prima ( -B 1) o dopo ( -A 1). Mi dispiace che non potrei essere di maggiore aiuto.
Robert Riedl,
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.