sed
L'API est primitive - et c'est par conception. Au moins, il est resté primitif par sa conception - je ne peux pas dire s'il a été conçu primitivement au début. Dans la plupart des cas, l'écriture d'un sed
script qui, lorsqu'il est exécuté, produira un autre sed
script est en effet une question simple. sed
est très souvent appliqué de cette manière par des préprocesseurs macro tels que m4
et / ou make
.
(Ce qui suit est un cas d'utilisation hautement hypothétique: il s'agit d'un problème conçu pour convenir à une solution. Si cela vous semble un peu exagéré, c'est probablement parce qu'il l'est, mais cela ne le rend pas nécessairement moins valide.)
Considérez le fichier d'entrée suivant:
cat <<"" >./infile
camel
cat dog camel
dog cat
switch
upper
lower
Si nous voulions écrire un sed
script qui ajouterait le mot- case à la fin de chaque mot approprié dans le fichier d'entrée ci-dessus uniquement s'il pouvait être trouvé sur une ligne dans le contexte approprié , et nous souhaitions le faire le plus efficacement possible ( comme cela devrait être notre objectif, par exemple, lors d'une opération de compilation), nous devons donc éviter autant que possible d' appliquer des /
expressions rationnelles /
.
Une chose que nous pourrions faire est de pré-éditer le fichier sur notre système en ce moment et de ne jamais appeler sed
du tout pendant la compilation. Mais si l'un de ces mots dans le fichier doit ou ne doit pas être inclus en fonction des paramètres locaux et / ou des options de compilation, le faire ne serait probablement pas une alternative souhaitable.
Une autre chose que nous pourrions faire est de traiter le fichier maintenant contre les expressions rationnelles. Nous pouvons produire - et inclure dans notre compilation - un sed
script qui peut appliquer des modifications en fonction du numéro de ligne - ce qui est généralement un itinéraire beaucoup plus efficace à long terme.
Par exemple:
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|'
... qui écrit la sortie sous forme de sed
script et qui ressemble à ...
#!/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
Lorsque cette sortie est enregistrée dans un fichier texte exécutable sur ma machine nommée ./bang.sed
et exécutée comme ./bang.sed ./infile
, la sortie est:
camel-case
upper-case
lower-case
Maintenant, vous pourriez me demander ... Pourquoi voudrais-je faire ça? Pourquoi ne devrais-je pas simplement ancrer grep
des matchs? Qui utilise la camel case de toute façon? Et à chaque question à laquelle je ne pouvais que répondre, je n'en ai aucune idée ... parce que non. Avant de lire cette question, je n'avais jamais personnellement remarqué le multi-! analyse syntaxique dans la spécification - je pense que c'est une prise assez soignée.
Le multi-! Cependant, cela a immédiatement eu un sens - une grande partie de la sed
spécification est orientée vers des sed
scripts simplement analysés et générés simplement . Vous trouverez probablement les \n
délimiteurs ewline requis pour [wr:bt{]
avoir beaucoup plus de sens dans ce contexte, et si vous gardez cette idée à l'esprit, vous pourriez mieux comprendre certains autres aspects de la spécification - (comme l' :
acceptation d'aucune adresse et le q
refus de accepter plus de 1) .
Dans l'exemple ci - dessus , je vous écris une certaine forme de sed
scénario qui ne peut jamais être lu une fois. Si vous le regardez attentivement, vous remarquerez peut-être que lors de la sed
lecture du fichier d'édition, il progresse d'un bloc de commande à l'autre - il ne se dérive jamais ou ne termine son script d'édition jusqu'à ce qu'il soit complètement terminé avec son fichier d'édition.
Je considère que multi-! les adresses pourraient être plus utiles dans ce contexte que dans certains autres, mais, en toute honnêteté, je ne peux pas penser à un seul cas dans lequel j'aurais pu l'utiliser à bon escient - et moi sed
beaucoup. Je pense également qu'il convient de noter que les deux GNU / BSD sed
ne parviennent pas à le gérer comme spécifié - ce n'est probablement pas un aspect de la spécification qui est très demandé, et donc si une implémentation l'ignore, je doute très sérieusement que leurs bugs @ box souffriront terriblement en conséquence.
Cela dit, le fait de ne pas gérer cela comme spécifié est un bogue pour toute implémentation qui prétend être conforme, et je pense donc que l'envoi d'un e-mail aux boîtes de développement pertinentes est nécessaire ici, et j'ai l'intention de le faire si vous ne le faites pas.
!
agit comme une bascule,/pattern/!!
est le même que/pattern/
et/pattern/!!!
est le même que/pattern/!
. Sur FreeBSD, plusieurs!
sont identiques à un seul.