sed
A API é primitiva - e isso é por design. Pelo menos, ele permaneceu primitivo por design - se ele foi concebido primitivamente desde o início, não posso dizer. Na maioria dos casos, a escrita de um sed
script que, quando executado, produzirá outro sed
script, é realmente uma questão simples. sed
é frequentemente aplicado dessa maneira por pré-processadores de macro como m4
e / ou make
.
(O que se segue é um caso de uso altamente hipotético: é um problema projetado para se adequar a uma solução. Se parecer um esticamento para você, provavelmente é porque é, mas isso não necessariamente o torna menos válido.)
Considere o seguinte arquivo de entrada:
cat <<"" >./infile
camel
cat dog camel
dog cat
switch
upper
lower
Se desejássemos escrever um sed
script que anexasse a palavra -case à cauda de cada palavra apropriada no arquivo de entrada acima, apenas se ele pudesse ser encontrado em uma linha no contexto apropriado , e desejássemos fazê-lo da maneira mais eficiente possível ( como deve ser nosso objetivo, por exemplo, durante uma operação de compilação) , devemos preferir evitar aplicar o máximo de /
regexp /
s.
Uma coisa que podemos fazer é pré-editar o arquivo em nosso sistema agora e nunca ligar sed
durante a compilação. Mas se alguma dessas palavras no arquivo deve ou não ser incluída com base nas configurações locais e / ou nas opções de tempo de compilação, isso provavelmente não seria uma alternativa desejável.
Outra coisa que podemos fazer é processar o arquivo agora contra regexps. Podemos produzir - e incluir em nossa compilação - um sed
script que pode aplicar edições de acordo com o número da linha - que normalmente é uma rota muito mais eficiente a longo prazo.
Por exemplo:
n=$(printf '\\\n\t')
grep -En 'camel|upper|lower' <infile |
sed " 1i${n%?}#!/usr/heirloom/bin/posix2001/sed -nf
s/[^:]*/:&$n&!n;&!b&$n&/;s/://2;\$a${n%?}q"'
s/ *cat/!/g;s/ *dog/!/g
s| *\([cul][^ ]*\).*|s/.*/\1-case/p|'
... que grava a saída na forma de um sed
script e que se parece com ...
#!/usr/heirloom/bin/posix2001/sed -nf
:1
1!n;1!b1
1s/.*/camel-case/p
:2
2!n;2!b2
2!!s/.*/camel-case/p
:5
5!n;5!b5
5s/.*/upper-case/p
:6
6!n;6!b6
6s/.*/lower-case/p
q
Quando essa saída é salva em um arquivo de texto executável na minha máquina chamado ./bang.sed
e executado como ./bang.sed ./infile
, a saída é:
camel-case
upper-case
lower-case
Agora você pode me perguntar ... Por que eu iria querer fazer isso? Por que eu não apenas ancorava grep
os fósforos? Quem usa o estojo de camelo, afinal? E para cada pergunta que eu só podia responder, não faço ideia ... porque não faço. Antes de ler esta pergunta, eu nunca havia notado pessoalmente o multi-! requisito de análise nas especificações - acho que é uma captura bem legal.
O multi-! coisa que imediatamente faz sentido para mim, embora - a maior parte da sed
especificação é voltado para simplesmente analisados e simplesmente gerados sed
scripts. Você provavelmente encontrará os \n
delimitadores de linha eletrônica necessários para [wr:bt{]
fazer muito mais sentido nesse contexto, e se você mantiver essa ideia em mente, poderá entender melhor alguns outros aspectos da especificação - (como :
não aceitar endereços e q
se recusar a aceite mais de 1) .
No exemplo acima, eu escrevo uma certa forma de sed
script que só pode nunca ser lido uma vez. Se você observar bem, poderá perceber que, à medida que sed
lê o arquivo de edição, ele progride de um bloco de comando para o próximo - ele nunca se afasta ou completa seu script de edição até que termine completamente com seu arquivo de edição.
Eu considero isso multi-! endereços podem ser mais úteis nesse contexto do que em alguns outros, mas, honestamente, não consigo pensar em um único caso em que eu possa tê-lo usado muito bem - e sed
muito. Também acho digno de nota que sed
ambos os GNU / BSD não conseguem lidar com isso conforme especificado - esse provavelmente não é um aspecto da especificação que é muito requisitado e, portanto, se uma implementação a ignora, duvido muito seriamente que seus bugs @ box sofrerão terrivelmente como resultado.
Dito isso, a falha em lidar com isso como especificado é um bug para qualquer implementação que pretenda conformidade, e por isso acho que enviar um email para as caixas de desenvolvimento relevantes é necessário aqui, e pretendo fazê-lo, se não o fizer.
!
atua como uma alternância,/pattern/!!
é o mesmo que/pattern/
e/pattern/!!!
é o mesmo que/pattern/!
. No FreeBSD, múltiplos!
são iguais a um único.