Como truncar longas linhas correspondentes retornadas por grep ou ack

91

Eu quero executar ack ou grep em arquivos HTML que geralmente têm linhas muito longas. Não quero ver linhas muito longas que se quebram repetidamente. Mas eu quero ver apenas aquela parte de uma linha longa que envolve uma string que corresponde à expressão regular. Como posso fazer isso usando qualquer combinação de ferramentas Unix?

dan
fonte
1
O que é ack? É um comando que você usa quando não gosta de algo? Algo assim ack file_with_long_lines | grep pattern? :-)
Alok Singhal
6
@Alok ack(conhecido como ack-grepno Debian) usa grepesteróides. Também tem a --thppptopção (não é brincadeira). betterthangrep.com
ZoogieZork
Obrigado. Aprendi algo hoje.
Alok Singhal
1
Enquanto o --thppptrecurso é um tanto controverso, a principal vantagem parece ser que você pode usar Perl expressões regulares diretamente, e não algum louco [[:space:]]e personagens como {, [, etc. mudando significando com o -ee -Emuda de uma forma que é impossível lembrar.
Evgeni Sergeev

Respostas:

101

Você pode usar a opção grep -o, possivelmente em combinação com a alteração de seu padrão para ".{0,10}<original pattern>.{0,10}", a fim de ver algum contexto em torno dele:

       -o, --only-matching
              Mostra apenas a parte de uma linha correspondente que corresponda a PATTERN.

..ou -c :

       -c, --count
              Suprime a saída normal; em vez disso imprima uma contagem de linhas correspondentes
              para cada arquivo de entrada. Com a opção -v, --invert-match (veja
              abaixo), conte as linhas não correspondentes.
Éter
fonte
44
um exemplo: grep -oE ". {0,20} mysearchstring. {0,20}" myfile
Renaud
14
você deve alterar a resposta para adicionar a opção -E conforme mostrado por @Renaud (opção de padrão estendido), ou o padrão proposto para estender o contexto não funcionará.
Kriss
Talvez não seja necessário, mas aqui está um exemplo: $ echo "eeeeeeeeeeeeeeeeeeeeqqqqqqqqqqqqqqqqqqqqMYSTRINGwwwwwwwwwwwwwwwwwwwwrrrrrrrrrrrrrrrrrrrrr" > fileonelongline.txt && grep -oE ".{0,20}MYSTRING.{0,20}" ./fileonelongline.txt impressõesqqqqqqqqqqqqqqqqqqqqMYSTRINGwwwwwwwwwwwwwwwwwwww
Ulises Layera
1
Isso funciona bem; mas a desvantagem notável é que ao usar, por exemplo, oE ".{0,20}mysearchstring.{0,20}"você perde o destaque da string "original" interna em relação ao contexto, porque a coisa toda se torna o padrão de pesquisa. Adoraria encontrar uma maneira de manter algum contexto não destacado em torno dos resultados da pesquisa, para facilitar a digitalização visual e a interpretação dos resultados.
Aaron Wallentine de
1
Oh, aqui está uma solução para o problema de realce causado pelo uso da -oE ".{0,x}foo.{0,x}"abordagem (onde xestá o número de caracteres do contexto) - anexar `| grep foo `até o fim. Funciona para soluções ack ou grep. Mais soluções também aqui: unix.stackexchange.com/questions/163726/…
Aaron Wallentine,
45

Canalize seus resultados cut. Também estou pensando em adicionar um --cutswitch para que você possa dizer --cut=80e obter apenas 80 colunas.

Andy Lester
fonte
8
E se a parte correspondente não estiver nos primeiros 80 caracteres?
Ether
3
FWIW eu anexei | cut=c1-120ao grep, funcionou para mim (embora não saiba como cortar o texto correspondente)
Jake Rayson
26
| cut=c1-120não funcionou para mim, eu precisava fazer| cut -c1-120
Ken Cochrane
1
Acho que @edib é preciso na sintaxe | cut -c 1-100 stackoverflow.com/a/48954102/1815624
CrandellWS
1
@AndyLester: Que tal uma --no-wrapopção que usa $COLUMNS?
naught101
25

Você poderia usar o less como um pager para ack e cortar linhas longas: ack --pager="less -S" isso mantém a linha longa, mas a deixa em uma linha em vez de quebrar. Para ver mais da linha, vá para a esquerda / direita em menos com as teclas de seta.

Tenho o seguinte alias configurado para ack para fazer isso:

alias ick='ack -i --pager="less -R -S"' 
Jonah Braun
fonte
2
Observe que você pode colocar esse --pagercomando em seu arquivo ~ / .ackrc, se sempre quiser usá-lo.
Andy Lester
Esta parece ser a melhor solução para este problema que me incomoda muito. Eu gostaria de saber como usar ack.
Brian Peterson,
@BrianPeterson acké muito parecido grep, apenas mais simples nos casos mais comuns
Aaron Wallentine
8
cut -c 1-100

obtém caracteres de 1 a 100.

edib
fonte
2

Retirado de: http://www.topbug.net/blog/2016/08/18/truncate-long-matching-lines-of-grep-a-solution-that-preserves-color/

A abordagem sugerida ".{0,10}<original pattern>.{0,10}"é perfeitamente boa, exceto pelo fato de que a cor de realce costuma ser confusa. Eu criei um script com uma saída semelhante, mas a cor também é preservada:

#!/bin/bash

# Usage:
#   grepl PATTERN [FILE]

# how many characters around the searching keyword should be shown?
context_length=10

# What is the length of the control character for the color before and after the
# matching string?
# This is mostly determined by the environmental variable GREP_COLORS.
control_length_before=$(($(echo a | grep --color=always a | cut -d a -f '1' | wc -c)-1))
control_length_after=$(($(echo a | grep --color=always a | cut -d a -f '2' | wc -c)-1))

grep -E --color=always "$1" $2 |
grep --color=none -oE \
    ".{0,$(($control_length_before + $context_length))}$1.{0,$(($control_length_after + $context_length))}"

Supondo que o script seja salvo como grepl, grepl pattern file_with_long_linesdeve exibir as linhas correspondentes, mas com apenas 10 caracteres ao redor da string correspondente.

xuhdev
fonte
Funciona, mas resulta em lixo eletrônico para mim, como este: ^ [[? 62; 9; c. Não tentei depurar porque a resposta de @Jonah Braun me satisfez.
sondra.kinsey
2

insira a descrição da imagem aqui

Na situação incomum em que você não pode usar -E, você pode usar:

grep -oe ".\{0,10\}error.\{0,10\}" mylogfile.txt
Josh Withee
fonte
1

Aqui está o que eu faço:

function grep () {
  tput rmam;
  command grep "$@";
  tput smam;
}

No meu .bash_profile, eu sobrescrevo grep para que ele seja executado automaticamente tput rmamantes e tput smamdepois, o que desabilitou o empacotamento e então o reativou.

ognockocaten
fonte
Essa é uma boa alternativa - exceto se a partida real estiver fora da tela ...
Xerus
0

Eu coloco o seguinte em meu .bashrc:

grepl() {
    $(which grep) --color=always $@ | less -RS
}

Você pode então usar greplna linha de comando com quaisquer argumentos disponíveis para grep. Use as setas do teclado para ver a cauda das linhas mais longas. Use qpara sair.

Explicação:

  • grepl() {: Defina uma nova função que estará disponível em cada (novo) console bash.
  • $(which grep): Obtenha o caminho completo de grep. (Ubuntu define um alias para grepisso é equivalente a grep --color=auto. Não queremos esse alias, mas o original grep.)
  • --color=always: Colorir a saída. ( --color=autodo alias não funcionará, pois grepdetecta que a saída é colocada em um tubo e não a colorirá.)
  • $@: Coloque todos os argumentos fornecidos para a greplfunção aqui.
  • less: Exibir as linhas usando less
  • -R: Mostrar cores
  • S: Não quebre longas filas
pt1
fonte