Pesquise uma sequência e imprima tudo antes e depois dentro de um intervalo


9

Eu tenho este arquivo:

sometext1{
string1
}

sometext2{
string2
string3
}

sometext3{
string4
string5
string6
}

Desejo procurar neste arquivo uma sequência específica e imprimir tudo antes dessa sequência até a abertura {e tudo depois dessa sequência até o fechamento }. Eu tentei conseguir isso com o sed, mas se eu tentar imprimir tudo no intervalo, /{/,/string2/por exemplo, sed imprime isso:

sometext1{
string1
}

sometext2{
string2
sometext3{
string4
string5
string6
}

Se eu procurar a string "string2", preciso que a saída seja:

sometext2{
string2
string3
}

Obrigado.


Bem, agora descobri que preciso dos números de linha da saída no arquivo original para excluí-los mais tarde. Tentei mudar o comando que o @mikeserv forneceu sem sorte, estou um pouco confuso com a função hold do sed.
Rodrigo

bem, nossa, rodrigo, você não contou a ninguém além de você. Isso pode ser feito, mas é melhor assim grep -n '' <infile | sed .... Os sedcomandos precisarão ser modificados; especificamente os bits de /endereço /que procuram por ^âncoras top de linha. Então, se você estava usando a minha resposta você provavelmente poderia fazer: grep -n '' | sed 'H;/{$/h;/^[^:]*:}/x;/{\n.*PATTERN/!d'. Todas as linhas de saída serão prefixadas com os números de linha do arquivo original, seguidos por dois pontos 1:sometext1{\n2:string1e assim por diante. sedfiltrará apenas o que filtraria antes, exceto que cada linha de saída é aberta com um número.
mikeserv

Respostas:


9

Aqui estão dois comandos. Se você deseja um comando que apare até a última .*{$linha em uma sequência (como @don_crissti faz com ed), você pode:

sed 'H;/{$/h;/^}/x;/{\n.*PATTERN/!d'

... que funciona anexando todas as linhas ao Hespaço antigo, seguindo um \ncaractere ewline, substituindo o hespaço antigo por todas as linhas correspondentes {$e trocando hespaços antigos e padrão por cada linha correspondente ^}- e, assim, liberando seu buffer.

Ele só imprime linhas que correspondem a {uma linha de \new e, PATTERNem seguida, em algum momento - e isso só acontece imediatamente após uma troca de buffer.

Ele elimina todas as linhas de uma série de {$correspondências até a última da sequência, mas você pode obter todas as inclusivas, como:

sed '/PATTERN.*\n/p;//g;/{$/,/^}/H;//x;D'

O que ele faz é trocar o padrão e hos espaços antigos para cada ...{$.*^}.*sequência, anexa todas as linhas da sequência ao Hespaço antigo após um \ncaractere de linha de linha e Delimina o primeiro \ncaractere de linha de ew que ocorre no espaço de padrão para cada ciclo de linha antes de começar novamente com o que resta.

Obviamente, a única vez em que ele recebe \newline no espaço do padrão é quando uma linha de entrada corresponde ^}- o final do seu intervalo - e, portanto, quando ele executa o script novamente em qualquer outra ocasião, ele apenas puxa a próxima linha de entrada normalmente.

Porém, quando PATTERNé encontrado no mesmo espaço de padrão que uma linha de \new, imprime o lote antes de substituí-lo ^}novamente (para que possa terminar o intervalo e liberar o buffer) .

Dado este arquivo de entrada (obrigado don) :

sometext1{
string1
}

sometext2{
PATTERN
string3
}

sometext3{
string4
string5
string6
}

Header{
sometext4{
some string

string unknown

here's PATTERN and PATTERN again
and PATTERN too
another string here
}
}

As primeiras impressões:

sometext2{
PATTERN
string3
}
sometext4{
some string

string unknown

here's PATTERN and PATTERN again
and PATTERN too
another string here
}

...e o segundo...

sometext2{
PATTERN
string3
}
Header{
sometext4{
some string

string unknown

here's PATTERN and PATTERN again
and PATTERN too
another string here
}

@don_crissti - eu não sei. É única delimita a sequência para um início de linha com }. Isso pode ser benéfico para ... open{\nsub;\n{ command; }\n}; close- mas não tenho certeza de que é o que está acontecendo aqui ... #
mikeserv #:

Oi @ mikeserv - Eu tenho uma pergunta semelhante que é levantada aqui unix.stackexchange.com/questions/232509/… , sua solução funciona em um arquivo pequeno, mas eu tenho um arquivo grande e estou recebendo "Espaço em espera excedido". mensagem de erro. Alguma chance você sabe, como eu poderia resolver isso? Muito obrigado
Narayan Akhade 28/09/2015

@NarayanAkhade - no. não sem uma revisão, de qualquer maneira. a menos que ... haja grandes extensões de entrada que não estejam contidas em {...}blocos? Se for esse o caso e você estiver usando a primeira solução, poderá fazê-lo /{$/,/^}/Hno início, em vez de apenas H. Mas se você também tentou a segunda solução e ainda encontrou o mesmo erro, provavelmente não ajudará, porque essa já faz isso. E também não desconte ed. don tem uma resposta muito boa aqui e edpode ser aplicada para usar arquivos temporários de buffer com muita simplicidade, o que deve impedir a saturação do buffer de memória.
mikeserv

6

Aqui está uma solução com ed:

ed -s filename <<< $'g/PATTERN/?{?,/}/p\nq\n'

isso é:

g/PATTERN/     # mark each line matching PATTERN  
?{?,/}/p       # for each marked line, print all lines from the previous { up to the next }  
q              # quit editor

Isso pressupõe que há apenas uma linha PATTERNentre cada par de, { }caso contrário, você obterá uma saída duplicada para cada linha adicional PATTERNdentro do mesmo bloco.
Ele funcionará para múltiplos que { }contêm uma única linha correspondente, PATTERNpor exemplo, para um arquivo de teste PATTERNem duas seções diferentes:

sometext1{
string1
}

sometext2{
PATTERN
string3
}

sometext3{
string4
string5
string6
}

Header{
sometext4{
some string

string unknown

here's PATTERN again

another string here
}
}

corrida

ed -s sample <<< $'g/PATTERN/?{?,/}/p\nq\n'

saídas:

sometext2{
PATTERN
string3
}
sometext4{
some string

string unknown

here's PATTERN again

another string here
}

Eu tirei muito disso, na verdade! Muito obrigado!
mikeserv

Eu nem sei que esse comando existe. Graças
rodrigo

4

Com pcregrep:

pcregrep -M '(?s)\{[^}]*PATTERN.*?\}'

Ou com o GNU, grepdesde que a entrada não contenha NUL bytes:

grep -Poz '.*(?s)\{[^}]*PATTERN.*?\}'

0
$ awk 'BEGIN{RS="\n\n"; FS="[{}]"} {if ($2 ~ /string4/) {print $2}}' t1.txt
string4
string5
string6

Onde:

  • string4 -> string a ser correspondida
  • t1.txt -> contém o conteúdo do arquivo mencionado na consulta

-2

nome do arquivo sed -n '/ string / p'

o -n quando adicionado ao sed suprimiu o comportamento padrão do sed, esta declaração pode não fornecer exatamente o que você deseja, mas deve apenas deslocar a string

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.