Imprimir somente após encontrar o padrão


13

Existe um script (vamos chamá-lo echoer) que é impresso para exibir um monte de informações. Eu gostaria de poder ver apenas as linhas depois que um padrão for encontrado.

Eu imagino o uso de uma solução para parecer algo como

echoer | solution_command <pattern>

Idealmente, patternseria uma expressão regular, mas cadeias de valor rígidas seriam suficientes para mim.


Então, o padrão pode ser várias strings?
Inian 28/03/19

Uma glob? Você quer dizer uma expressão regular? Os globos só fazem sentido para expansões de nome de arquivo.
terdon

@Inian Não sei se entendi a pergunta. Você quer perguntar se eu quero que isso funcione com disjunções?
user23146

Respostas:


21

O AWK pode fazer isso com intervalos de padrões, o que permite o uso de qualquer expressão regular:

echoer | awk '/pattern/,0'

imprimirá echoera saída começando com a primeira linha correspondente pattern.

O AWK é baseado em padrões e geralmente é usado com um tipo de abordagem "se esse padrão corresponder, faça isso". “Esse padrão” pode ser um intervalo de padrões, definido como “quando esse padrão corresponder, comece a fazer isso até que outro padrão corresponda”; isso é especificado escrevendo dois padrões separados por vírgula, como acima. Os padrões podem ser correspondências de texto, como em /pattern/, onde a linha atual é comparada com o padrão, interpretada como uma expressão regular; eles também podem ser expressões gerais, avaliadas para cada linha e consideradas correspondentes se o resultado for diferente de zero ou não vazio.

No AWK, a ação padrão é imprimir a linha atual.

Juntando tudo isso, awk '/pattern/,0'procura as linhas correspondentes patterne, uma vez encontrada, aplica a ação padrão a todas as linhas até que a 0condição corresponda (seja diferente de zero). awk '/pattern/,""'funcionaria também.

O manual do Gawk entra em muito mais detalhes.


3
Eu não estava ciente da semântica do intervalo com zero no final do intervalo. Obrigado!
Kusalananda

@StephenKitt Isso é ótimo! E se eu quisesse imprimir até que correspondesse 0? Seria /pattern/,/0/? Como seria a resposta ao escrever explicitamente a ação padrão?
user23146

@ user23146 sim, /pattern/,/0/seria impresso até encontrar uma linha (registro) contendo “0”. Escrever o snippet na resposta com uma ação explícita fornece /pattern/,0 { print $0 }ou equivalente /pattern/,0 { print }.
Stephen Kitt

7

O sedequivalente obrigatório do de StephenKitt awk:

sed '/pattern/,$!d'

patterné interpretada como uma Expressão regular básica como em grep(em oposição à Expressão regular estendida em awk/ egrep/ grep -E). Algumas sedimplementações têm uma opção -E(BSD, ast, recente GNU / busybox, em breve POSIX) ou -r(GNU, ssed, busybox, algum recente BSD) para torná-lo Expressões regulares estendidas e outras têm -P(ast) ou -R(ssed) para torná-lo uma expressão regular semelhante a perl.

Com perl:

perl -ne 'print if /pattern/ .. undef'

4

com GNU e * BSD grep:

grep -A1000000000 pattern file

A menos que seu arquivo tenha mais de 1 milhão de linhas, é isso.


0

Se você estiver usando um pager, como lesspara visualizar a saída do comando

less +pattern

0

awk para linhas após (mas não incluindo) a primeira correspondência de padrão

Se a linha que contém o padrão de disparo é equivalente a "CORTE AQUI", você pode omiti-lo na saída impressa:

echoer | awk 'flag ; /pattern/ { flag=1 }'

Cada linha de entrada é executada através de dois componentes no código awk. O primeiro componente é flag, que o awk interpreta como "imprime a linha se a variável flagfor diferente de zero". Como as variáveis ​​awk são 0 por padrão, isso inicialmente não imprimirá nada.

O segundo componente, /pattern/ { flag=1 }define o sinalizador para 1 assim que detectar o padrão, e o sinalizador mantém esse valor pelo resto da execução.

Quando o padrão é detectado pela primeira vez, a oportunidade de imprimir essa linha de entrada já passou. Quaisquer linhas subsequentes (incluindo linhas adicionais contendo o padrão) serão impressas.


0

Bater

Um pouco desajeitado, mas funciona.

#!/bin/bash
found=false
while IFS= read -r; do
    if $found || [[ $REPLY =~ pattern ]]; then
        found=true
        printf '%s\n' "$REPLY"
    fi
done

Esta versão depende cat, mas é mais fácil de entender.

#!/bin/bash
while IFS= read -r; do
    if [[ $REPLY =~ pattern ]]; then
        printf '%s\n' "$REPLY"
        break
    fi
done
cat
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.