Como procurar um arquivo de texto por strings entre dois tokens no terminal Ubuntu e salvar a saída?

5

Como posso pesquisar um arquivo de texto para este padrão no terminal do Ubuntu e salvar a saída como um arquivo de texto?

Estou procurando por tudo entre a string "abc" e a string "cde" em uma longa lista de dados.

Por exemplo:

blah blah abc fkdljgn cde blah
blah blah blah blah blah abc skdjfn cde blah

No exemplo acima, eu estaria procurando uma saída como esta:

fkdljgn
skdjfn

É importante que eu também possa salvar a saída de dados como um arquivo de texto.

Posso usar grep ou agrep? Em caso afirmativo, qual é o formato?

    
por Blue 04.06.2014 / 13:19

2 respostas

11

Para obter a saída exibida, você pode executar

grep -Po 'abc \K.*(?= cde)'  file.txt > outfile.txt

O P ativa Expressões regulares compatíveis com Perl que têm suporte para lookarounds e \K , o que significa " descartar qualquer coisa correspondida até este ponto ". O -o faz com que grep imprima apenas a parte correspondida da linha. Assim, combinada com a antecipação positiva ( ?=cde ) e a \K , será impressa apenas os caracteres entre abc e cde . O > outfile.txt salvará o resultado no arquivo outfile.txt .

Algumas outras abordagens:

  • sed

    sed -r 's/.*abc (.+) cde.*//' file.txt > outfile.txt
    

    Aqui, os parênteses capturam o padrão e você pode se referir a ele como . O 's/source/replacement/' é o operador de substituição e substitui source por replacement . Neste caso, ele simplesmente excluirá tudo, exceto o que estiver entre abc e cde .

  • perl

    perl -pe 's/.*abc (.+) cde.*/$1/' file.txt > outfile.txt
    

    O mesmo que acima, o -p significa "leia o arquivo de entrada linha a linha, aplique o script dado como -e e imprima.

  • awk

     awk -F'abc|cde' '{print $2}' file.txt > outfile.txt
    

    A ideia aqui é definir os delimitadores de campo como abc ou cde . Supondo que essas seqüências são exclusivas em cada linha, o segundo campo será o único entre os dois. Isso, no entanto, inclui espaços iniciais e finais, para removê-los e passar por outro awk :

    awk -F'abc|cde' '{print $2}' file | awk '{print $1}'
    
  • GNU awk ( gawk ). O acima funciona perfeitamente em gawk , estou incluindo isso caso você queira fazer algo mais complexo e precisar capturar padrões.

    gawk '{print gensub(/.*abc (.*) cde.*/,"\1", "g",$0);}' file.txt > outfile.txt
    

    Esta é a mesma ideia básica dos perl e sed , mas usando o .

por 04.06.2014 / 15:17
3

Você deseja usar uma expressão regular para isso. Eu não sou tão experiente com o regex UNIX, mas algo assim deve funcionar

grep -Po '(?<=abc ).*(?= cde)' test.txt > output.txt

Edit: O erro de sintaxe veio de citações faltantes, embora a sugestão antiga não funcionasse, você prefere usar (?<=xxx) , isso é chamado de asserção de look-behind com largura zero e sem < você olha para frente . -P para ativar o regex de estilo perl e -o para imprimir apenas as correspondências.

Tentei isso e estou trabalhando bem com um arquivo de texto contendo abc mymatch cde .

    
por 04.06.2014 / 13:35