sed
Die API von ist primitiv - und dies ist beabsichtigt. Zumindest ist es von Grund auf primitiv geblieben - ob es von Anfang an primitiv entworfen wurde, kann ich nicht sagen. In den meisten Fällen ist das Schreiben eines sed
Skripts, das beim Ausführen ein anderes sed
Skript ausgibt , in der Tat eine einfache Angelegenheit. sed
wird sehr oft von Makro-Präprozessoren wie m4
und / oder auf diese Weise angewendet make
.
(Was folgt, ist ein sehr hypothetischer Anwendungsfall: Es ist ein Problem, das speziell für eine Lösung entwickelt wurde. Wenn es sich für Sie wie eine Ausdehnung anfühlt, liegt das wahrscheinlich daran, aber das macht es nicht unbedingt weniger gültig.)
Betrachten Sie die folgende Eingabedatei:
cat <<"" >./infile
camel
cat dog camel
dog cat
switch
upper
lower
Wollten wir ein sed
Skript schreiben, das das Wort- case nur dann an das Ende jedes entsprechenden Wortes in der obigen Eingabedatei anfügt , wenn es in einer Zeile in einem geeigneten Kontext gefunden werden kann , und wollten dies so effizient wie möglich tun (/
Da dies unser Ziel sein sollte, zum Beispiel während eines Kompiliervorgangs, sollten wir es vorziehen, Regexps /
so weit wie möglich zu vermeiden .
Eine Sache, die wir tun könnten, ist, die Datei auf unserem System vorab zu bearbeiten und sie sed
während der Kompilierung niemals aufzurufen . Wenn jedoch eines dieser Wörter in der Datei auf der Grundlage lokaler Einstellungen und / oder Optionen zur Kompilierungszeit enthalten sein sollte oder nicht, wäre dies wahrscheinlich keine wünschenswerte Alternative.
Eine andere Möglichkeit besteht darin, die Datei jetzt gegen reguläre Ausdrücke zu verarbeiten. Wir können ein sed
Skript erstellen - und in unsere Zusammenstellung aufnehmen -, das Bearbeitungen entsprechend der Zeilennummer vornehmen kann - was auf lange Sicht in der Regel eine weitaus effizientere Route darstellt.
Beispielsweise:
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|'
... der die Ausgabe in Form eines sed
Skripts schreibt und so aussieht ...
#!/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
Wenn diese Ausgabe in einer ausführbaren Textdatei auf meinem Computer mit dem Namen gespeichert wird ./bang.sed
und wie ./bang.sed ./infile
folgt ausgeführt wird , lautet die Ausgabe:
camel-case
upper-case
lower-case
Jetzt fragst du mich vielleicht ... Warum sollte ich das tun wollen? Warum sollte ich nicht einfach grep
die Streichhölzer ankern ? Wer benutzt schon Camel-Case? Und auf jede Frage konnte ich nur antworten, ich habe keine Ahnung ... weil ich es nicht tue. Bevor ich diese Frage gelesen habe, war mir das Multi-! Parsing-Anforderung in der Spezifikation - Ich denke, es ist ein ziemlich ordentlicher Fang.
Die Multi-! Für mich ergab das jedoch sofort einen Sinn - ein Großteil der sed
Spezifikation ist auf einfach analysierte und einfach generierte sed
Skripte ausgerichtet. Sie werden wahrscheinlich die erforderlichen \n
ewline-Begrenzer finden, [wr:bt{]
um in diesem Kontext viel sinnvoller zu sein, und wenn Sie diese Idee berücksichtigen, könnten Sie einige andere Aspekte der Spezifikation besser verstehen - wie das :
Akzeptieren von Adressen und das q
Ablehnen von Adressen akzeptiere mehr als 1) .
Im obigen Beispiel schreibe ich eine bestimmte Form von sed
Skript, die immer nur einmal gelesen werden kann. Wenn Sie es sich genauer ansehen, werden Sie feststellen, dass es beim sed
Lesen der Bearbeitungsdatei von einem Befehlsblock zum nächsten weitergeht - es verzweigt nie von seinem Bearbeitungsskript weg oder vervollständigt es, bis es vollständig mit seiner Bearbeitungsdatei fertig ist.
Ich halte das für multi-! Adressen mögen in diesem Zusammenhang nützlicher sein als in einigen anderen, aber ehrlich gesagt, fällt mir kein einziger Fall ein, in dem ich ihn möglicherweise sehr gut genutzt hätte - und ich sed
sehr viel. Ich halte es auch für bemerkenswert, dass GNU / BSD sed
beide nicht wie angegeben damit umgehen - dies ist wahrscheinlich kein Aspekt der Spezifikation, der stark nachgefragt wird, und wenn eine Implementierung es übersieht, bezweifle ich, dass ihre bugs @ box darunter leiden wird schrecklich als Ergebnis.
Das heißt, die Nichtbeachtung dieser Vorgaben ist ein Fehler für jede Implementierung, die sich als konform ausgibt. Ich denke, hier ist es angebracht, eine E-Mail an die entsprechenden Entwickler-Boxen zu senden, und ich beabsichtige, dies zu tun, wenn Sie dies nicht tun.
!
fungiert es als Toggle,/pattern/!!
ist dasselbe wie/pattern/
und/pattern/!!!
ist dasselbe wie/pattern/!
. Unter FreeBSD sind mehrere!
gleich einem einzelnen.