Qual é o sentido de usar vários pontos de exclamação no sed?

11

documentação do POSIX sed disse:

A function can be preceded by one or more '!' characters, in which case the function shall be applied if the addresses do not select the pattern space. Zero or more <blank> characters shall be accepted before the first '!' character. It is unspecified whether <blank> characters can follow a '!' character, and conforming applications shall not follow a '!' character with <blank> characters.

Assim, com qualquer sed POSIX, podemos:

sed -e '/pattern/!d' file

É o mesmo que escrever:

sed -e '/pattern/!!d' file

E !!!d e n de pontos de exclamação ainda estão bem (Testado com três sed versão de heirloom toolchest ). Não vejo nenhum benefício entre vários em vez de uma exclamação.

Por que a especificação permitiu essa sintaxe e como ela é útil no mundo real?

Parece que o GNU sed não é compatível neste caso, ele irá reclamar se usarmos várias exclamações:

$ sed -e '/pattern/!!d' file
sed: -e expression #1, char 11: multiple '!'s
    
por cuonglm 22.06.2015 / 17:15

1 resposta

4
A API de

sed é primitiva - e isso é por design. Pelo menos, ele permaneceu primitivo por design - quer tenha sido projetado primitivamente no início, não posso dizer. Na maioria dos casos, a escrita de um script sed que, quando executado, produzirá outro sed script é uma questão simples. sed é frequentemente aplicado dessa forma por pré-processadores de macro, como m4 e / ou make .

(O que se segue é um caso de uso altamente hipotético: trata-se de um problema projetado para se adequar a uma solução. Se parece um trecho para você, provavelmente é porque é, mas isso não necessariamente é menos válido.)

Considere o seguinte arquivo de entrada:

cat <<"" >./infile
camel
cat dog camel
dog cat
switch
upper
lower

Se quiséssemos escrever um script sed que acrescentaria a palavra -case ao final de cada palavra apropriada no arquivo de entrada acima somente se pudesse ser encontrado em uma linha em contexto apropriado , e nós desejamos fazê-lo tão eficientemente quanto possível (como deveria ser nosso objetivo, por exemplo, durante uma operação de compilação) então deve preferir evitar aplicar o / regexp / s o máximo possível.

Uma coisa que podemos fazer é pré-editar o arquivo em nosso sistema agora, e nunca chamar sed durante a compilação. Mas se qualquer uma 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, fazer isso provavelmente não seria uma alternativa desejável.

Outra coisa que podemos fazer é processar o arquivo agora contra regexps. Nós podemos produzir - e incluir em nossa compilação - um script sed 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/.*/-case/p|'

... que grava a saída na forma de um script sed 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 em minha máquina chamada ./bang.sed e executada 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 ancoraria as combinações de grep ? Quem usa o caso do camelo mesmo assim? E para cada pergunta eu só poderia responder, eu não tenho idéia ... porque eu não sei. Antes de ler esta pergunta, eu nunca tinha notado pessoalmente o requisito de análise multi -! na especificação - eu acho que é uma boa idéia.

O multi -! coisa fez imediatamente faz sentido para mim - muito da especificação sed é voltada para simplesmente analisada e simplesmente gerada sed scripts. Você provavelmente achará que os delimitadores \n ewline necessários para [wr:bt{] fazem muito mais sentido nesse contexto, e se você mantiver essa idéia em mente, poderá ter uma melhor noção de alguns outros aspectos da especificação - ( como : sem aceitar endereços e q se recusando a aceitar mais do que 1) .

No exemplo acima eu escrevo uma certa forma de sed script que só pode ever ser lida uma vez. Se você olhar com atenção para isso, poderá notar que, como sed lê o arquivo de edição, ele progride de um bloco de comando para o seguinte - ele nunca separa ou conclui seu script de edição até que seja completamente finalizado. arquivo.

Eu considero que os endereços multi -! podem ser mais úteis nesse contexto do que em outros, mas, na honestidade, não consigo pensar em um único caso em que eu possa ter dito para muito bom uso - e eu sed muito. Eu também acho que é digno de nota que GNU / BSD sed s não conseguem lidar com isso como especificado - este provavelmente não é um aspecto da especificação que é muito demandada, então se uma implementação negligencia, eu duvido seriamente que eles > Bugs @ caixa irá sofrer terrivelmente como resultado.

Dito isto, a falha em lidar com isso como é um bug para qualquer implementação que pretenda ser compatível, então acho que filmar um e-mail para os dev boxes relevantes é chamado aqui, e eu pretendo fazê-lo se você não fizer isso.

    
por 24.06.2015 / 02:08

Tags