Como posso aparar um arquivo (fluxo de entrada do poço) para obter apenas as linhas que vão da primeira ocorrência do padrão foo
à última ocorrência do padrão bar
?
Por exemplo, considere a seguinte entrada:
A line
like
foo
this
foo
bar
something
something else
foo
bar
and
the
rest
Espero esta saída:
foo
this
foo
bar
something
something else
foo
bar
text-processing
sed
rahmu
fonte
fonte
foo
e o últimobar
e imprimiria tudo o que havia entre eles. Com um fluxo, você teria que ler até o primeirofoo
e armazenar em buffer todas as linhas subseqüentes na memória até o EOF, liberando o buffer sempre quebar
for visto. Isso pode significar armazenar em buffer todo o fluxo na memória.Respostas:
A correspondência do padrão sed
/first/,/second/
lê as linhas uma a uma. Quando alguma linha corresponde a/first/
ela, ela se lembra e aguarda a primeira correspondência do/second/
padrão. Ao mesmo tempo, aplica todas as atividades especificadas para esse padrão. Após esse processo, é iniciado novamente e novamente até o final do arquivo.Não é disso que precisamos. Precisamos procurar a última correspondência de
/second/
padrão. Portanto, construímos construções que parecem apenas para a primeira entrada/foo/
. Quando encontrado, o cicloa
começa. Adicionamos nova linha ao buffer de correspondênciaN
e verificamos se ele corresponde ao padrão/bar/
. Se isso acontecer, basta imprimi-lo e limpar o buffer de correspondência e o janyway jump para o início do ciclo comba
.Também precisamos excluir o símbolo de nova linha após a limpeza do buffer
/^\n/s/^\n//
. Tenho certeza de que existe uma solução muito melhor, infelizmente não veio à minha mente.Espero que tudo esteja claro.
fonte
sed
versões, por exemplo, BSD sed (que é encontrado nos Macs), as tags precisam ser seguidas por uma nova linha ou final de string, portanto é necessário o seguinte ajuste:sed -n -e '/foo/{:a' -e 'N;/^\n/s/^\n//;/bar/{p;s/.*//;};ba' -e '};'
Isso também funciona no GNU sed, então eu acho que essa modificação (vários-e
argumentos terminar um argumento após o nome de cada ramo) é um bom hábito portátil de se usar ao usar ramos no sed.Eu faria isso com um pouco de linha única de Perl.
rendimentos
fonte
E
vez dee
e em-00777
vez do$/
bit (veja perlrun (1)). O que reduziria para:,perl -0777 -nE 'say /(foo.*bar)/s'
ainda meio legível.-0[octal]
, ele encontrará seu caminho no meu fluxo de trabalho! Obrigado por issoAqui está uma solução GNU sed de duas passagens que não requer muita memória:
Explicação
sed
chamada passa infile e localiza a primeira ocorrência defoo
e todas as ocorrências subsequentes debar
.sed
script com duas invocações desed
e umtr
. Saída do terceirosed
é[start_address],[end_address]p
, sem os colchetes.sed
passesinfile
novamente, imprimindo os endereços encontrados e tudo mais.fonte
Se o arquivo de entrada couber confortavelmente na memória, mantenha-o simples .
Se o arquivo de entrada for enorme, você poderá
csplit
dividi-lo em pedaços no iníciofoo
e, a cada subseqüentebar
, montá- los . As peças são chamadaspiece-000000000
,piece-000000001
etc. Escolha um prefixo (aquipiece-
) que não entrará em conflito com outros arquivos existentes.(Em sistemas não Linux, você precisará usar um grande número dentro dos aparelhos, por exemplo
{999999999}
, e passar a-k
opção. Esse número é o número debar
peças.)Você pode montar todas as peças com
cat piece-*
, mas isso lhe dará tudo após a primeirafoo
. Então remova a última peça primeiro. Como os nomes dos arquivos produzidos porcsplit
não contêm caracteres especiais, você pode trabalhar com eles sem tomar nenhuma precaução especial de citação, por exemplo, comou equivalente
Agora você pode juntar todas as peças e remover os arquivos temporários:
Se você deseja remover as peças conforme são concatenadas para economizar espaço em disco, faça-o em um loop:
fonte
Aqui está outra maneira de
sed
:Anexa cada linha no
/foo/,$
intervalo (as linhas que!
não estão nesse intervalo sãod
excluídas) aoH
espaço antigo. As linhas que não correspondembar
são excluídas. Nas linhas correspondentes, o espaço do padrão é esvaziado, ex
alterado com o espaço de espera e a linha vazia inicial no espaço do padrão é removida.Com entrada enorme e poucas ocorrências,
bar
isso deve ser (muito) mais rápido do que colocar cada linha no espaço do padrão e, a cada vez, verificar o espaço do padrãobar
.Explicado:
Claro, se este é um arquivo (e cabe na memória), você pode simplesmente executar:
porque
ed
pode pesquisar para frente e para trás.Você pode até ler uma saída de comando no buffer de texto se o seu shell suportar a substituição do processo:
ou, se não, com
gnu ed
:fonte
Usando qualquer awk em qualquer shell em qualquer sistema UNIX e sem ler o arquivo inteiro ou o fluxo de entrada na memória ao mesmo tempo:
fonte
O Grep também pode fazê-lo (bem, GNU grep):
Para a entrada do corpo da pergunta:
fonte