awk "/^Entry '234238'/ {printline = 1; print; next}
/^Entry / {printline = 0}
printline"
Digamos que eu tenha um arquivo com informações da seguinte forma:
...
Entry '234238': some text
some text
some text
some text
Entry '899823': some text
some text
some text
Entry '234238': more text
more text
more text
Entry '645353': some text
some text
some text
Gostaria de extrair um Entry '<code>'
específico. Por exemplo, grep_my_block 'Entry '234238'
deve retornar:
Entry '234238': some text
some text
some text
some text
Entry '234238': more text
more text
more text
Observe que:
<code>
que identifica um bloco pode aparecer várias vezes no arquivo. Queremos extrair todos esses blocos. Como faço isso com grep
, awk
ou ack
?
ENTRY="'234238'"
sed -n ':s;/Entry '"$ENTRY"'/{:l;p;n;/^Entry/bs;bl;}' <<\ENTRY
Entry '234238': some text
some text
some text
some text
Entry '899823': some text
some text
some text
Entry '234238': more text
more text
more text
Entry '645353': some text
some text
some text
#END
ENTRY
Entry '234238': some text
some text
some text
some text
Entry '234238': more text
more text
more text
Isso deve ser muito mais rápido do que awk
(acho) devido a sed's
operações de fluxo.
Esse foi um dos menos complicados que fiz - uma vez que envolvi minha cabeça em torno dele. Este é um dos primeiros que consegui fazer sem requerer o regex estendido do GNU - isso deve ser bastante portátil.
Isso se ramifica duas vezes - há um achor :s
no início e uma âncora :l
para o subscrito. Isso funciona porque o operador n
exclui a linha anterior de sed's
pattern-space quando puxa uma nova.
Uma vez que sed
encontre o seu "$ENTRY"
, ele define o ramo :l
abel, imprime a linha e extrai um novo. Em seguida, sed
verifica se a nova linha começa com a frase 'Entry'
. Nesse caso, ela será ramificada para :s
tart rotular e começar a escanear sua entrada novamente para o seu "$ENTRY,"
senão ela só será ramificada até :l
abel e repetirá o p
rint, n
ext, /check/
operação.
Este comando resume-se ao seguinte:
until end of file do
if current line contains "Entry $ENTRY" do
until next line contains 'Entry' do
print line
delete line
next line
done
done
done
Você também pode usar pcregrep
:
pcregrep -M '234238.*(\n((?!Entry).)*)*' inputfile
Isso produziria todas as linhas, começando da que continha 234238
até encontrar uma que contenha a palavra Entry
.
Para sua entrada de amostra, ela produz:
Entry '234238': some text
some text
some text
some text
Entry '234238': more text
more text
more text
awk
é provavelmente uma boa ferramenta para usar, já que o problema é orientado à linha.
Eu usaria essa variante da solução @ HaukeLaging, que tem menos redundância no código. Cada linha que começa com Entry
limpa um sinalizador, mas o cabeçalho da entrada específica que você deseja define o sinalizador. Se o sinalizador estiver definido, execute a ação padrão de imprimir a linha.
awk "/^Entry / { printline=0; }
/^Entry '234238'/ { printline=1; }
printline"
Tags text-processing