Imprime texto entre dois padrões

0

Eu preciso:

Print text between "hi" and "hello" patterns.

Os padrões podem ser repetidos e pode haver várias ocorrências de hi .. hello .

Arquivo de origem:

hi aa bb cc
dd ee ff
hello xxxxxx
aaaa dddd cccc hi aaa bbb
ccc hello cccc fff

Saída esperada.

hi aa bb cc
dd ee ff
hello
hi aaa bbb
ccc hello

Eu tentei usar os comandos awk e sed -n , enquanto exibe toda a linha entre a primeira ocorrência de hi e a última ocorrência de hello .

    
por user314870 09.10.2018 / 08:20

3 respostas

2

Do primeiro olá ao primeiro olá que segue.

grep

Usando (GNU) grep e tr:

$ <infile grep -oPz "(?s)hi.*?hello" | tr '
<infile sed 's/hi/\n&/;s/[^\n]*\n//;s/\(hello\).*//;/hi/,/hello/!d'
' '\n' hi aa bb cc dd ee ff hello hi aaa bbb ccc hello

Descrição:

  • <infile arquivo de origem.
  • grep -oPz Chame grep para:
    • ( -P ) corresponde a um P CRE (expressão regular compatível com Perl)
    • ( -o ) o simplesmente imprima a peça correspondente.
    • ( -z ) usa um z ero byte (também conhecido como NUL e a.k.a. "(?s) ) como delimitador de linha.
  • . Faça com que o ponto PCRE ( hi ) coincida com as novas linhas.
  • hi Começando com a string .*? .
  • ? Coincidir com todos os caracteres que seguem (não gananciosos por causa de hello" ).
  • hello Até a string | tr 'grep -z' '\n' ser correspondida.
  • \n Converte os bytes NULs ( s/// ) (de newline ) em novas linhas.

sed

GNU sed:

$ eval "$(printf "nl='\n'")"

Ou, para o BSD sed, que não permite nl no lado direito de %code% , você precisa definir um %code% variable %code% :

<infile sed 's/hi/\'"$nl"'&/;s/[^\n]*\n//;s/\(hello\).*//;/hi/,/hello/!d'

E então:

<infile sed 's/hi/\
&/;s/[^\n]*\n//;s/\(hello\).*//;/hi/,/hello/!d'

Ou; se você pudesse escrever uma nova linha explícita:

$ <infile grep -oPz "(?s)hi.*?hello" | tr '
<infile sed 's/hi/\n&/;s/[^\n]*\n//;s/\(hello\).*//;/hi/,/hello/!d'
' '\n' hi aa bb cc dd ee ff hello hi aaa bbb ccc hello
    
por 09.10.2018 / 09:05
0
grep -oPz "(?s)hi.*?hello" fileName

Explicação abaixo.

cat tmp

Saída - >

hi aa bb cc
dd ee ff
hello xxxxxx
aaaa dddd cccc hi aaa bbb
ccc hello cccc fff
00000000000
hi ff 
djd h
sdkf hello
dfj 

Solução:

grep -oPz "(?s)hi.*?hello" tmp

Saída - >

hi aa bb cc
dd ee ff
hello
hi aaa bbb
ccc hello
hi ff 
djd h
sdkf hello

Params:

  • -z esta opção diz ao grep para tratar as novas linhas como caracteres de texto comuns e procura bytes nulos para separar registros. Em um arquivo de texto sem bytes nulos, grep -z tratará o arquivo inteiro como uma linha.

  • (?s) ativar PCRE_DOTALL, o que significa que '.' encontra qualquer caractere ou nova linha.

  • o Imprime apenas a parte correspondente

  • -P Interprete o padrão como uma expressão regular compatível com Perl (PCRE). Isso é altamente experimental, especialmente quando combinado com a opção -z (-null-data), e "grep -P" pode avisar sobre recursos não implementados.

  • .*? Para correspondência não-gananciosa. Comece a procurar a próxima correspondência de hi quando encontrar a primeira instância de hello

    Fonte: link

por 09.10.2018 / 08:54
0

awk para risadinhas

#!/usr/bin/awk -f
{
    n=split($0, col, FS)
    for(i=1;i<=n;i++){
        (i==n)? sp="" : sp=FS
        if (col[i] ~ /hi/) p=1
        if (p == 1  && col[i] ~ /hello/) h=1
        if (p == 1) printf("%s%s",col[i],sp)
        if (h==1) p=0;h=0
    }
    printf "\n"
}



kapu@jake:$ cat SourceFile
hi aa bb cc
dd ee ff
hello xxxxxx
aaaa dddd cccc hi aaa bbb
ccc hello cccc fff
kapu@jake:$ script.awk SourceFile
hi aa bb cc
dd ee ff
hello
hi aaa bbb
ccc hello
    
por 10.10.2018 / 22:52