Vamos ignorar a compressão por enquanto. Você deseja produzir as linhas entre A
e B=1
, mas apenas se ambas aparecerem. O sed
que você usou não fará isso, já que ele começa a produzir assim que A
é visto e não verifica B=1
. Poderíamos usar o buffer de retenção em sed
para manter tudo até que B=1
seja encontrado, mas estou mais confortável com awk
, então aqui:
$ echo -en 'not this\nA\nthis\nB=1\nnot this\n' |
awk '/A/ {save=1} save {data = data $0 ORS} /B=0/ {save=0; data=""} /B=1/ {save=0; printf "%s", data; data=""} '
A
this
B=1
A regra B=0
lida com blocos que não devem ser impressos.
Em seguida, manipule a compactação e vários arquivos.
O find
+ xargs
que você fez funciona, mas se alguns arquivos puderem ter blocos parciais ( A
sem B
), concatenar os arquivos juntos causará problemas. Assumindo que não é o caso, podemos apenas colocar o awk no final:
$ find . -name foo\*.gz -print0 | xargs -0 zcat | \
awk '/A/ {s=1} s {d = d $0 ORS} /B=0/ {s=0; d=""}
/B=1/ {s=0; printf "%s", d; d=""} '
Se precisarmos lidar com blocos parciais, teremos que lidar com cada arquivo separadamente:
$ find . -name foo\*.gz -print0 | xargs -0 sh -c '
for f; do zcat "$f" | awk '\''/A/ {s=1} s {d = d $0 ORS}
/B=0/ {s=0; d=""} /B=1/ {s=0; printf "%s", d; d=""} '\''; done' sh
A citação é horrível, portanto, o script awk
provavelmente deve ter um arquivo próprio.
Ou apenas faça isso no shell (Bash / ksh / zsh):
$ shopt -s globstar # set -o globstar in ksh
$ for f in **/*.gz ; do zcat "$f" |
awk '/A/ {s=1} s {d = d $0 ORS} /B=0/ {s=0; d=""}
/B=1/ {s=0; printf "%s", d; d=""} ' ; done
Se quiser imprimir apenas as linhas intervenientes (não as linhas A
e B=1
), troque as posições dos blocos /A/ {...}
e /B=.../ {...}
.