in Bezug auf tragbare sed-e ... db oder! b?

12

In dieser Bearbeitung POSIXifiziert Stéphane Chazelas (erneut) meine Formatierung, indem er eine xpression break- Anweisung und eine andere xpression-Anweisung einfügt. Nun, ich könnte ihn vielleicht fragen, warum in den Kommentaren, nehme ich an, aber es ist bereits die Revision Nummer 18 zu dieser Antwort und fast alle vorherigen waren bereits ähnlichen Werbegeschenken zu verdanken (wenn Sie gelöschte Kommentare sehen können, wissen Sie was Ich meine) . Ich denke auch, dass ich nahe genug dran bin, um zu verstehen, warum man dies in einer Weise formuliert, die allgemeiner nützlich sein könnte. Also hier ist die Hoffnung ... sed-e-e

Im Allgemeinen ziehe ich es vor, meinen sed -eGesamtdruck auf einen zu beschränken, aber ich habe auch eine größere Vorliebe dafür, mich so nah wie möglich an die Spezifikation zu halten , insbesondere wenn der Unterschied nicht mehr als a <space>und an beträgt -e. Aber ich kann das nicht tun, wenn ich nicht verstehe, warum ich sollte. Hier ist ein kurzer Überblick über den aktuellen Stand meines Verständnisses:

  • Die ' -e 'Unterbrechung kann portabel für eine sedSkript- \nE sed-Line- Unterbrechung in einer Befehlszeilenanweisung stehen ... Ich bin zugegebenermaßen unklar, warum

  • Der schließenden Klammer in einer sed {Funktion }muss ein \newline-Umbruch vorausgehen, wie hier angegeben:

    • Dem <right-brace>muss ein vorangestellt sein <newline>und es können <blank>Zeichen vorangestellt oder gefolgt werden .
  • eine \newline Pause wird nach jeder Verwendung auf ähnliche Weise erforderlich ... a, b, c, i, r, t, w, oder :.

Aber ich verstehe nicht klar, wie sich die {Funktionsdefinition }auf den !Nicht-Operator bezieht . Die einzige Erwähnung, die ich vom Negationsoperator in der Spezifikation finde, ist:

  • Einer Funktion können ein oder mehrere !Zeichen vorangestellt werden. In diesem Fall wird die Funktion angewendet, wenn die Adressen den Musterraum nicht auswählen.

Bedeutet dies, dass die Verwendung eines Klammern !impliziert ? Was ist mit Befehlen - sollten sie ebenfalls durch Pausen getrennt sein ? Wurde dies angesprochen, als Stéphane zuletzt meine Antwort POSIXifizierte ?{}$!' -e '

Ich denke, es ist entweder der !Negationsoperator oder es ist die bRanch-Anweisung, die er in seiner Bearbeitung anspricht - oder möglicherweise beides gleichzeitig -, aber ich weiß es nicht und möchte es. Wenn es nur die bRanch Aussage, dann glaube ich , ein dan seiner Stelle tun würde , und die Notwendigkeit der Beseitigung ' -e 'Pause, aber ich würde lieber sicher sein , bevor sie eine dreimal hazarding POSIXified Antwort. Kannst du helfen?

Ich habe es riskieren , schließlich , aber nicht mit großer Sicherheit ...

mikeserv
quelle
Mit b;n;:bverzweigen Sie zu dem Label, das ";n;:b"in historischen und POSIX-Seds genannt wird (und GNU sed ist diesbezüglich nicht der Fall).
Stéphane Chazelas
@ StéphaneChazelas - Ich verstehe das :Teil - du bist das vor Monaten nach Hause gefahren. Aber ich verstehe nicht ganz, warum der zweite sedBefehl ähnlich POSIXified war .
mikeserv
1
In jedem Fall sedist mir die POSIX-Spezifikation für sehr unklar. Ich habe in der Vergangenheit einige Male um Klarstellungen gebeten, aber ich glaube nicht, dass es als Ergebnis aktualisiert wurde. Ein guter Test ist der Versuch mit der Erbstück-Werkzeugkiste (Solaris, eine vom Original abgeleitete, auf der die POSIX-Spezifikation weitgehend basiert).
Stéphane Chazelas
1
@syntaxerror - ich glaube nicht, dass das der Fall ist. Wenn Sie die Spezifikation lesen, s///werden Sie feststellen, dass Substitutionen die Verkettung mit einem akzeptieren ; . Kommandos, die mit einem Zeilenumbruch abgegrenzt werden müssen, werden verschwommen und wie -ekann man in diesem Fall stehen - zumindest für mich. Ich bin noch nicht auf eine sedgestoßen, die sie allerdings nicht wirklich austauschbar interpretiert.
mikeserv
1
@syntaxerror - es gefällt mir, aber du solltest wissen, dass du das nicht brauchst, ;bevor eine neue Zeile - eine neue Zeile ist in Ordnung. Ehrlich gesagt, Sie könnten-e ganz auf das und alles verzichten und einfach eine Datei wie #!/bin/sedmit jedem Befehl in eine neue Zeile schreiben - oder solche, die keine solchen Trennzeichen benötigen, stattdessen mit ;. Diejenigen , die tun newlines erfordern , sind in der Regel diejenigen , die beliebige Eingaben nehmen - :Markennamen und Befehle , die sich auf sie beziehen , wie boder toder Schließen }curlies für Funktionen oder read und wRitus , die Dateinamen args nehmen. Sie alle müssen tragbar gefolgt werden \n.
mikeserv

Antworten:

4

Es ist also höchste Zeit, dass diese Frage beantwortet wird, und obwohl ich vor einiger Zeit so gut wie immer intuitiv herausgefunden habe, wie man das richtig macht, habe ich es erst vor kurzem geschafft, dieses Verständnis mit dem Text in der Norm einigermaßen zu konkretisieren . Es heißt dort eigentlich ziemlich einfach - ich habe es nur dumm oft übersehen, denke ich.

Die relevanten Teile des Textes befinden sich alle unter der Überschrift ...

  • Befehle bearbeiten insed :

    • Das Argument Text setzt sich aus einer oder mehreren Linien bestehen. \nVor jeder eingebetteten ewline im Text muss ein \Backslash stehen. Andere Backslashes im Text werden entfernt und das folgende Zeichen wird wörtlich behandelt.

    • Die rund wBefehlsverben und das wFlag an den sBefehl, nehmen eine optionale RDATEI (oder wfile ) Parameter, von dem Befehlsverb Buchstaben oder Flag durch einen oder mehrere getrennt <blank>s; Implementierungen können eine Trennung von Null als Erweiterung ermöglichen.

    • Befehlsverb andere als {, a, b, c, i, r, t, w, :, und #kann durch eine folgen ;Semikolon, optional <blank>s, und ein anderes Befehlsverb. Wenn jedoch das sBefehlsverb mit dem wFlag verwendet wird, führt das Verfolgen mit einem anderen Befehl auf diese Weise zu undefinierten Ergebnissen.

...im...

  • Optionen: Es können mehrere -eund -fOptionen angegeben werden. Alle Befehle müssen unabhängig von ihrer Herkunft in der angegebenen Reihenfolge zum Skript hinzugefügt werden.

    • -e script - Fügen Sie die durch das script- Optionsargument angegebenen Bearbeitungsbefehle am Ende des Skripts der Bearbeitungsbefehle hinzu. Das Skript - Option-Argument hat die gleichen Eigenschaften wie das hat Skript Operanden in dem beschriebenen OPERANDS Abschnitt.

    • -f script_file - Fügen Sie die Bearbeitungsbefehle in der Datei script_file am Ende des Skripts hinzu.

Und zuletzt in ...

  • Operanden:

    • script - Ein String, der als Skript zum Bearbeiten von Befehlen verwendet wird. Der Antrag darf kein Skript enthalten , das gegen die Beschränkungen einer Textdatei verstößt, mit der Ausnahme, dass das letzte Zeichen keine \newline sein muss.

Wenn Sie also insgesamt davon ausgehen, ist es sinnvoll, dass jeder Befehl, auf den optional ein beliebiger Parameter ohne vordefinierten Begrenzer folgt (im Gegensatz zum s d sub d repl d flagBeispiel), an einer nicht entkappten \newline begrenzt wird.

Es ist fraglich , dass das ; ist eine vordefinierte Trennzeichen , aber in diesem Fall ist die Verwendung ;für alle [aic]Befehle erfordern würde , dass ein separater Parser bei der Umsetzung für diese drei Befehle speziell einbezogen werden - getrennt, die vom Parser für verwendet wird [:brw], zum Beispiel. Andernfalls müsste für die Implementierung ; auch ein Backslash innerhalb des text- Parameters angegeben werden, der von da an nur noch komplizierter wird.

Wenn ich eine schreiben würde sed, die sowohl konform als auch effizient sein soll, würde ich vermutlich keinen solchen separaten Parser schreiben - außer, dass möglicherweise [aic]ein Syntaxfehler \nauftritt, wenn nicht sofort eine ewline folgt. Dies ist jedoch ein einfaches Tokenisierungsproblem - der Fall des Endbegrenzers ist im Allgemeinen problematischer. Ich würde es einfach so schreiben:

sed -e w\ file\\ -e one -e '...;and more commands'

...und...

sed -e a\\ -e appended\\ -e text -e '...;and more commands'

... würde sich insofern sehr ähnlich verhalten, als der erste eine Datei mit dem Namen erstellen und in diese schreiben würde:

file
one

... und der zweite würde bei der Ausgabe einen Textblock an die aktuelle Zeile anhängen wie ...

appended
text

... weil beide denselben Parsing-Code für den Parameter verwenden würden.

Und in Bezug auf das Thema { ... }und $!- nun, ich war weit weg. Ein einzelner Befehl, dem eine Adresse vorangestellt ist, ist keine Funktion, sondern nur ein adressierter Befehl. Fast alle Befehle - einschließlich der { Funktionsdefinition - } sind zum Akzeptieren /one/oder /one/,/two/Adressieren angegeben - mit Ausnahme von #Kommentaren und :Beschriftungsdefinition werden . Und eine Adresse kann entweder eine Zeilennummer oder ein regulärer Express sein und kann mit negiert werden !. Also alles von ...

$!d
/address/s/ub/stitution/
5!y/d/c/

... kann gefolgt werden von a ; standardmäßig und mehreren Befehlen Wenn jedoch mehrere Befehle für eine einzelne Adresse erforderlich sind und diese Adresse nach der Ausführung jedes Befehls nicht erneut ausgewertet {werden }soll, sollte eine Funktion wie folgt verwendet werden:

/address/{ s//replace addressed pattern/
           s/do other conditional/substitutions/
           s/in the same context/without/
           s/reevaluating/address/
}

... wo {kann nicht in der gleichen Zeile von einem Closing }und einem Closing gefolgt werden} nur am Zeilenanfang erfolgen kann. Wenn einem enthaltenen Befehl jedoch keine \newline folgen soll, muss er auch nicht in der Funktion enthalten sein. Auf alle obigen s///Substitutionen - und sogar auf die schließende }Klammer - können also ;Semikolons und weitere Befehle portabel folgen .

Ich spreche immer über \newline-Begrenzer, aber die Frage ist stattdessen über -expression-Anweisungen, ich weiß. Aber die beiden sind wirklich ein und dasselbe, und die Schlüsselbeziehung ist, dass ein Skript entweder ein Literalbefehlszeilenargument oder eine Datei mit einem von beiden sein -[ef]kann und dass beide als Textdateien interpretiert werden (die angegeben werden, um mit a zu enden) \newline) aber weder Bedarf tatsächlich am Ende in einem \newline. Auf diese Weise kann ich vernünftigerweise (wie ich hoffe) schließen, dass ein \0NULbegrenztes Argument eine endende \newline impliziert , und da alle Aufrufargumente mindestens ein \0NULTrennzeichen haben, sollte beides gut funktionieren.

In der Tat, in der Praxis, in jedem Fall, außer einem, wo die Norm einen mit \Backslash-Escape versehenen Zeilenumbruch vorschreibt, habe ich tragbar festgestellt, dass ...

sed -e ... -e '...\' -e '...'

... genauso gut zu arbeiten. Und in jedem Fall - auch in der Praxis - wo eine nicht \nentkoppelte ewline benötigt werden sollte ...

sed -e '...' -e '...'

... hat auch für mich gearbeitet. Die einzige Ausnahme, die ich oben erwähne, ist ...

sed -e 's/.../...\' -e '.../'

... was bei keiner Implementierung in einem meiner Tests funktioniert. Ich bin ziemlich sicher , dass wieder auf den fällt Textdatei Bedarf und die Tatsache , dass s/// kommt mit einem Trennzeichen und so gibt es keinen Grund , eine einzige Aussage sollte umspannt \0NULbegrenzt Argumente.

Im Folgenden finden Sie eine kurze Übersicht über die portablen Möglichkeiten, verschiedene Arten von sedBefehlen zu schreiben :

Für irgendeinen von [aic]:

...commands;[aic]\
text embedded newline\
delimiting newline
...more;commands...

...oder...

sed -e '...commands;[aic]\' -e 'text embedded newline\' -e 'delimiting newline' -e '.;.;.'

Für alle , [:rwtb]wo der Parameter ist optional (für alle , aber :) , aber die Begrenzungs \newline ist nicht . Beachten Sie, dass ich habe noch nie einen Grund mehrzeilige versuchen Etikett als Parameter würde verwendet werden [:tb], aber das writing / reading auf mehrere Zeilen in [rw] file Parameter in der Regel ohne Frage akzeptiert seds ich so lange wie das eingebettete getestet \newline wird mit einem \Backslash entkommen . Die Norm spezifiziert diese Kennzeichnungsparameter Parameter für und [rw] -Datei identisch mit dem Text analysiert werden sollen jedoch nicht direkt und erwähnt ewlines in Bezug auf die ersten beiden nicht, es sei denn, sie begrenzen sie.\n

...commands;[:trwb] parameter
...more;commands...

...oder...

sed -e '[:trwb] parameter' -e '...'

... wo das <space>obige optional ist für [:tb].

Und zuletzt...

...;address[!]{ ...function;commands...
};...more;commands....

...oder...

sed -e '...;address[!]{ ...function;commands...' -e '};...more;commands...'

... wobei eine der vorgenannten Befehle ( mit Ausnahme :) auch mindestens eine annehmen Adresse und die entweder eine sein kann /regexp /oder eine Zeilennummer und möglicherweise mit negiert werden !, aber wenn mehr als ein Befehl für eine einzelne Auswertung der notwendig ist , Adresse dann Klammern zur Begrenzung des {Funktionskontexts }müssen verwendet werden. Eine Funktion kann sogar mehrere \newline-getrennte Befehle enthalten, die jedoch innerhalb der geschweiften Klammern voneinander getrennt sein müssen, wie dies sonst der Fall wäre.

Und so schreiben Sie portable sedSkripte.

mikeserv
quelle
2
Warum akzeptierst du nicht deine eigene Antwort?
Philippos