Limita a saída do grep a linhas curtas

6

Costumo usar o grep para encontrar arquivos com uma determinada entrada como esta:

grep -R 'MyClassName'

O bom é que ele retorna os arquivos, seu conteúdo e marca a string encontrada em vermelho. O ruim é que eu também tenho arquivos enormes onde o texto inteiro é escrito em uma única linha grande. Agora o grep produz muito quando encontra texto dentro desses arquivos grandes. Existe uma maneira de limitar a saída para, por exemplo, 5 palavras à esquerda e à direita? Ou talvez limitar a saída para 30 letras à esquerda e à direita?

    
por Socrates 18.04.2018 / 10:19

2 respostas

14

grep em si só tem opções para contexto baseado em linhas. Uma alternativa é sugerida por esta postagem SU :

A workaround is to enable the option 'only-matching' and then to use RegExp's power to grep a bit more than your text:

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

Of course, if you use color highlighting, you can always grep again to only color the real match:

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

Como outra alternativa, sugiro fold texto e, em seguida, grepping, por exemplo:

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

A opção -s fará com que fold empurrem as palavras para a próxima linha, em vez de quebrar entre elas.

Ou use outra forma de dividir a entrada em linhas com base na estrutura da sua entrada. (A postagem SU, por exemplo, lidava com JSON, portanto, usar jq etc. para pretty-print e grep ... ou apenas usar jq para fazer a filtragem por si só ... seria melhor do que das duas alternativas dadas acima.)

Este método do GNU awk pode ser mais rápido:

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
  • Diga ao awk para dividir os registros no padrão em que estamos interessados ( -v RS=... ) e o número de caracteres no contexto ( -v n=... )
  • Cada registro após o primeiro registro ( FNR > 1 ) é aquele em que o awk encontrou uma correspondência para o padrão.
  • Assim, imprimimos n caracteres finais da linha anterior ( p ) e n caracteres principais da linha atual ( substr($0, 0, n) ), juntamente com o texto correspondente da linha anterior (que é prt )
    • definimos p e prt após impressão, de modo que o valor que definimos é usado pela próxima linha
    • RT é um GNUism, é por isso que isso é específico do GNU para o awk.

Para pesquisa recursiva, talvez:

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}' {} +
    
por muru 18.04.2018 / 10:32
1

Usar somente correspondência em combinação com algumas outras opções (veja abaixo), pode ser muito parecido com o que você está procurando, sem a sobrecarga de processamento da regex mencionada na outra resposta

grep -RnHo 'MyClassName'
  • saída numérica n , mostre o número da linha da correspondência
  • H nome do arquivo, mostra o nome do arquivo no início da linha da partida
  • o corresponde apenas, mostre apenas a string matemática, não toda a linha
por Robert Riedl 18.04.2018 / 11:29