grep para retornar as linhas N e M antes e depois da partida


12

Eu sei que com grep eu posso usar os campos -Ae -Bpuxar as linhas anteriores e seguintes de uma partida.

No entanto, eles puxam todas as linhas entre a correspondência com base no número de linhas especificadas.

grep -r -i -B 5 -A 5 "match" 

Eu gostaria de receber apenas a 5 ª linha antes de um jogo ea 5 ª linha após a partida em adição à linha combinado e não obter as linhas entre.

Existe uma maneira de fazer isso com o grep?


1
Você poderia fazer isso colocando-o no sed. Acabei de testar isso e funcionou, mas só funcionou quando houve 1 correspondência exata no arquivo: grep -r -i -B 5 -A 5 "match" | sed -e 1b -e '$!d'
— Terrance

@Terrance, obrigado pela sugestão, como você mencionou, já que estou coletando milhares de linhas, isso não funcionará.
— Chollida # 10/18

Eu não acho que grep vai funcionar por si só ... Eu estou trabalhando em um script bash para você
— Joshua Besneatte

Sem problemas! Meio interessado em ver quais respostas você recebe. =)
— Terrance

isso está em um arquivo ou em vários arquivos?
— Joshua Besneatte

Respostas:


1

A ferramenta que você deseja usar é chamada peneirar. Este é basicamente um grep com esteróides. Grep em paralelo. O Sift tem uma enorme quantidade de opções para fazer exatamente o que você deseja - especificamente para retornar uma linha específica em relação a uma (s) correspondência (s) que pode / não pode ser seguida / precedida por algum texto.

Surpreende-me que o sift não seja o gnu convencional, pois foi escrito na linguagem go, mas é instalado no Linux muito bem. A TI pesquisa em paralelo usando todas as enormes quantidades de texto de cpus, onde o grep leva apenas algumas semanas para fazer o mesmo.

Peneire o site - veja exemplos


Bem-vindo ao AskUbuntu, obrigado por responder. Você precisa fornecer um exemplo de CLI que possa resolver esse problema específico, em vez de fornecer um link para o site da peneira. Este é um resumo de perguntas e respostas, obrigado.
— Bernard Wei

12

E se:

cat file
a
b
c
d
e
f match
g
h
i match
j
k
l
m
n
o

Então:

awk '
    {line[NR] = $0} 
    /match/ {matched[NR]} 
    END {
        for (nr in matched)
            for (n=nr-5; n<=nr+5; n+=5) 
                print line[n]
    }
' file
a
f match
k
d
i match
n

+1, mas você poderia explicar a semântica de /match/ {matched[NR]}? Eu nunca vi uma matriz ou variável como um comando inteiro. É colocar o número do registro atual de cada linha correspondente na matriz.
— 21418 Joe

Essa é uma singularidade estranha: se você fizer referência a um elemento da matriz sem atribuição, essa chave será adicionada à matriz (sem um valor). Em seguida, essa chave aparece na expressão key in array. O que estou fazendo é lembrar os números de linha onde o padrão aparece
— Glenn Jackman

6

Esta é basicamente a solução de Glenn, mas implementada com Bash, Grep e sed.

grep -n match file |
    while IFS=: read nr _; do
        sed -ns "$((nr-5))p; $((nr))p; $((nr+5))p" file
    done

Observe que números de linhas menores que 1 cometerão erros sed e números de linhas maiores que o número de linhas no arquivo não imprimirão nada.

Este é apenas o mínimo. Para fazê-lo funcionar recursivamente e lidar com o número de linhas acima, levaria algum tempo.


6

Não pode ser feito apenas grep. Se for eduma opção:

ed -s file << 'EOF' 
g/match/-5p\
+5p\
+5p
EOF  

O script basicamente diz: para cada correspondência de / match /, imprima a linha 5 linhas antes disso, depois 5 linhas depois disso, depois 5 linhas depois disso.


5
@ubashu Você acha que será mais útil para o OP dar um plano simples "não pode ser feito com grep"? Estou fornecendo o que acredito ser uma boa alternativa para resolver o problema do OP. Na Central de Ajuda: "Qual é a pergunta específica? Verifique se sua resposta fornece isso - ou uma alternativa viável. A resposta pode ser 'não faça isso', mas também deve incluir 'tente fazer isso' . "
— JOL

edé sempre uma resposta, porque edé o editor de texto padrão.
— dessert

5
@ubashu Embora não seja uma grepresposta, a resposta "Você não pode fazer isso com X, mas com Y, veja como" ainda é uma resposta válida, pois você não apenas responde à pergunta da OP, mas também fornece uma alternativa Isso funcionaria. Este é um tipo válido de resposta aqui.
— Thomas Ward

5
awk '/match/{system("sed -n \"" NR-5 "p;" NR "p;" NR+5 "p\" " FILENAME)}' infile

Aqui estamos usando a função do awk para chamar o comando externo para imprimir as linhas que o awk combinou com o padrão com a quinta linha antes e depois da partida.system(command)sedmatch

A sintaxe é fácil, você só precisa colocar o comando externo entre aspas duplas, assim como suas opções, e escapar do que deseja passar exatamente para o comando; tudo o mais relacionado às awkopções em si deve estar fora das aspas. Então, o abaixo sed :

"sed -n \"" NR-5 "p;" NR "p;" NR+5 "p\" " FILENAME

traduzir para:

sed -n "NR-5p; NRp; NR+5p" FILENAME

NRé o número da linha que corresponde ao padrão matche FILENAMEé o nome do arquivo de processamento atual que está passando awk.


2

usando o arquivo de texto de exemplo de @ glenn e usando perl em vez de awk:

$ perl -n0E 'say /(.*\n)(?=(?:.*\n){4}(.*match.*\n)(?:.*\n){4}(.*\n))/g' ex

dará os mesmos resultados, mas rodando mais rápido:

a
f match
k
d
i match
n

João, você está aparecendo na fila de revisão do LQ e o @waltinator votou para excluir, portanto, da próxima vez, seja um pouco mais detalhado ... ;-) Também marque +1 para tirá-lo da fila do LQ ... : P
— Fabby

1
@JJoao Fila de avaliações de baixa qualidade. Sua resposta provavelmente foi escolhida por ser um código de 90%.
— Wjandrea

1
@JJoao A cifra de 90% é apenas minha maneira de explicar. Não sei quais heurísticas são realmente usadas.
— Wjandrea

1
Menos café, mais escrita! @JJoao : D ;-): D
— Fabby

1
@Fabby: Sem nada café Funciona: D - provavelmente que iria aparecer na LCQ (= baixo fila de café)
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.