Personagens Grep antes e depois da partida?


144

Usando isto:

grep -A1 -B1 "test_pattern" file

produzirá uma linha antes e depois do padrão correspondente no arquivo. Existe uma maneira de exibir não linhas, mas um número especificado de caracteres?

As linhas no meu arquivo são muito grandes, então não estou interessado em imprimir a linha inteira, mas apenas observar a correspondência no contexto. Alguma sugestão de como fazer isso?


Respostas:


184

3 caracteres antes e 4 caracteres depois

$> echo "some123_string_and_another" | grep -o -P '.{0,3}string.{0,4}'
23_string_and

5
Uma boa resposta para pequenas quantidades de dados, mas ele começa a ficar lento quando você combina> 100 caracteres - por exemplo, no meu arquivo xml gigante, quero {1.200} antes e depois, e é muito lento para usar.
Benubird

3
A versão awk do @amit_g é muito mais rápida.
ssobczak

6
Não disponível no Mac OSX, portanto, na verdade, essa não é uma solução amplamente disponível. A versão -E (listada abaixo) é uma solução melhor. O que é -P? Leia em ... -P, --perl-regexp Interprete PATTERN como uma expressão regular do Perl (PCRE, veja abaixo). Isso é altamente experimental e o grep -P pode avisar sobre recursos não implementados.
Xo

2
No OSX, instale via: brew install homebrew/dupes/grepe execute-o como ggrep.
kenorb

1
Como está implícito no @Benubird, será impossível usá-lo em termos de desempenho em arquivos grandes com um ambiente moderadamente amplo desejado para o destino da correspondência.
matanster

113
grep -E -o ".{0,5}test_pattern.{0,5}" test.txt 

Isso corresponderá a até 5 caracteres antes e depois do seu padrão. A opção -o diz ao grep para mostrar apenas a correspondência e -E para usar uma expressão regular estendida. Coloque as aspas em torno de sua expressão, caso contrário, ela poderá ser interpretada pelo shell.


1
Boa resposta, interessante que ele está limitado a 2 ^ 8-1 para o comprimento nos {} para {0,255}obras {0,256}grep: invalid repetition count(s)
codemonkey

Isso parece ter um desempenho consideravelmente menor quando eu aumento o número de caracteres correspondentes (5 -> 25 -> 50), alguma idéia do porquê?
Adam Hughes

37

Você poderia usar

awk '/test_pattern/ {
    match($0, /test_pattern/); print substr($0, RSTART - 10, RLENGTH + 20);
}' file

2
Funciona muito bem, mesmo com arquivos um pouco maiores também
Touko

4
como você pode usar isso para encontrar várias correspondências por linha?
58528 Kooz00

1
Qual é o significado do primeiro número nos pares entre colchetes? Como os 0s em "grep -E -o". {0,5} test_pattern. {0,5} "test.txt"?
Lew Rockwell Fan

É realmente mais rápido, mas não tão preciso quanto a resposta do @ ekse.
Abdollah

24

Você quer dizer assim:

grep -o '.\{0,20\}test_pattern.\{0,20\}' file

?

Isso imprimirá até vinte caracteres de cada lado test_pattern. A \{0,20\}notação é como *, mas especifica de zero a vinte repetições em vez de zero ou mais. -oDiz para mostrar apenas a correspondência em si, e não a linha inteira.


Este comando não está funcionando para mim:grep: Invalid content of \{\}
Alexander Pravdin 9/17/17

0

Com gawk, você pode usar a função de correspondência:

    x="hey there how are you"
    echo "$x" |awk --re-interval '{match($0,/(.{4})how(.{4})/,a);print a[1],a[2]}'
    ere   are

Se você estiver de acordo com perluma solução mais flexível: A seguir, serão impressos três caracteres antes do padrão, seguidos pelo padrão real e, em seguida, 5 caracteres após o padrão.

echo hey there how are you |perl -lne 'print "$1$2$3" if /(.{3})(there)(.{5})/'
ey there how

Isso também pode ser aplicado a palavras em vez de apenas caracteres. A seguir, uma palavra será impressa antes da sequência de caracteres real.

echo hey there how are you |perl -lne 'print $1 if /(\w+) there/'
hey

A seguir, imprimirá uma palavra após o padrão:

echo hey there how are you |perl -lne 'print $2 if /(\w+) there (\w+)/'
how

A seguir, imprimirá uma palavra antes do padrão, depois a palavra real e depois uma palavra após o padrão:

echo hey there how are you |perl -lne 'print "$1$2$3" if /(\w+)( there )(\w+)/'
hey there how

0

Você pode usar o regexp grep para encontrar + segundo grep para destacar

echo "some123_string_and_another" | grep -o -P '.{0,3}string.{0,4}' | grep string

23_string_and

insira a descrição da imagem aqui


0

Nunca me lembrarei facilmente desses modificadores de comando enigmático, então peguei a resposta superior e a transformei em uma função no meu ~/.bashrcarquivo:


cgrep() {
    # For files that are arrays 10's of thousands of characters print.
    # Use cpgrep to print 30 characters before and after search patttern.
    if [ $# -eq 2 ] ; then
        # Format was 'cgrep "search string" /path/to/filename'
        grep -o -P ".{0,30}$1.{0,30}" "$2"
    else
        # Format was 'cat /path/to/filename | cgrep "search string"
        grep -o -P ".{0,30}$1.{0,30}"
    fi
} # cgrep()

Aqui está o que parece em ação:

$ ll /tmp/rick/scp.Mf7UdS/Mf7UdS.Source

-rw-r--r-- 1 rick rick 25780 Jul  3 19:05 /tmp/rick/scp.Mf7UdS/Mf7UdS.Source

$ cat /tmp/rick/scp.Mf7UdS/Mf7UdS.Source | cgrep "Link to iconic"

1:43:30.3540244000 /mnt/e/bin/Link to iconic S -rwxrwxrwx 777 rick 1000 ri

$ cgrep "Link to iconic" /tmp/rick/scp.Mf7UdS/Mf7UdS.Source

1:43:30.3540244000 /mnt/e/bin/Link to iconic S -rwxrwxrwx 777 rick 1000 ri

O arquivo em questão é uma linha contínua de 25K e é impossível encontrar o que você está procurando usando grep .

Observe as duas maneiras diferentes de chamar cgrepesse grepmétodo de paralelos .

Existe uma maneira "mais inteligente" de criar a função em que "$ 2" é passado apenas quando definido, o que economiza 4 linhas de código. Eu não tenho isso à mão. Algo como ${parm2} $parm2. Se eu o encontrar, revisarei a função e esta resposta.

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.