Was bedeutet: a; $! N; in einem sed Befehl?

10
$ (echo hello; echo there) | sed ':a;$!N;s/\n/string/;ta'
hellostringthere

Der obige sedBefehl ersetzt das neue Zeilenzeichen durch die Zeichenfolge "Zeichenfolge". Aber ich kenne die Bedeutung :a;$!N;s/\n/string/;tader einzelnen Anführungszeichen nicht. Ich kenne den Mittelteil s/\n/string/. Aber ich kenne die Funktion von first ( :a;$!N;) und last ( ta) nicht.

Avinash Raj
quelle
2
Bitte schauen Sie auf stackoverflow.com/questions/1251999/… .
Xiaodongjie
Was ist mit dem letzten Teil?
Avinash Raj
Der Befehl "t" verzweigt zu einer benannten Bezeichnung, wenn der letzte Ersatzbefehl den Musterbereich geändert hat.
Xiaodongjie

Antworten:

17

Dies sind die zugegebenermaßen kryptischen sedBefehle. Speziell (von man sed):

: label
         Label für b- und t-Befehle.

t label
         Wenn as /// seit dem Lesen der letzten Eingabezeile und seit dem letzten t- oder T-Befehl erfolgreich ersetzt wurde, dann verzweige nach label. Wenn die Bezeichnung weggelassen wird, verzweigen Sie zum Ende des Skripts.

n N Lesen / Anhängen der nächsten Eingabezeile in den Musterbereich.

Das von Ihnen veröffentlichte Skript kann also unterteilt werden (Leerzeichen zur besseren Lesbarkeit hinzugefügt):

sed ':a;  $!N;  s/\n/string/;  ta'
     ---  ----  -------------  --
      |     |        |          |--> go back (`t`) to `a`
      |     |        |-------------> substitute newlines with `string`
      |     |----------------------> If this is not the last line (`$!`), append the 
      |                              next line to the pattern space.
      |----------------------------> Create the label `a`.

Grundsätzlich könnte das, was dies tut, im Pseudocode als geschrieben werden

while (not end of line){
    append current line to this one and replace \n with 'string'
}

Sie können dies anhand eines komplexeren Eingabebeispiels etwas besser verstehen:

$ printf "line1\nline2\nline3\nline4\nline5\n" | sed ':a;$!N;s/\n/string/;ta'
line1stringline2stringline3stringline4stringline5

Ich bin mir nicht sicher, warum das !$gebraucht wird. Soweit ich das beurteilen kann, können Sie mit dieselbe Ausgabe erzielen

printf "line1\nline2\nline3\nline4\nline5\n" | sed ':a;N;s/\n/string/;ta'
Terdon
quelle
1
Das! $ Soll nicht mit der letzten Zeile übereinstimmen, IMO.
Braiam
@Braiam nicht sicher, das ist es $!nicht !$. Es könnte jedoch auch sein !Nund nicht $!.
Terdon
Ich habe versucht, die Texinfo-Seite zu analysieren, aber keine Verweise auf weder !Nnoch gefunden $!. Also denke ich immer noch, ob die letzte Zeile Newline oder EOF ist.
Braiam
4
Ich versuche, mir $!einen Adressbereich mit einem Postfix-Komplement-Operator vorzustellen - also $!N( Nüberall außer Adresse $) ist wirklich die gleiche Syntax wie so etwas wie m,n!d(alles löschen, außer Zeilen man n).
Steeldriver
:ist analog zum gotoLabel und war in der Tat :ein Goto- Label in der Thompson-Shell, daher war es den Leuten früher bekannt, sowohl
Sed-
0

Ich poste diese Antwort , da ich eine Menge Verwirrung über sehen , warum die letzte Zeile ist ausgeschlossen, wenn die Ausführung N(durch die Leitung Adressierung String $!) und weil die OP über die Bedeutung verwechselt wurde :a;$!N; in einem sed Befehl , nicht nur in dem spezifischen er geschrieben .

Nun, der Vorteil der Verwendung von $!Nanstelle von Nist in den vorgeschlagenen Beispielen (vom OP und von @terdon) nicht ersichtlich, da in der letzten Zeile nach dem NBefehl kein "wichtiger" Befehl (weiterlesen) ausgeführt wird . (In der Tat ist das Ergebnis dasselbe, wenn man diese Leitungsadresse entfernt.)

In einem komplexeren Beispiel (z. B. Ersetzen this sentencein einer Datei, wobei die beiden Wörter manchmal in einer Zeile und manchmal in zwei Zeilen erscheinen) kann Nes entscheidend sein , die letzte Zeile für den Befehl auszuschließen ! Wenn die letzte Zeile nicht ausgeschlossen wird N, sedtrifft sie beim Ausführen EOFsofort und wird sofort beendet, wodurch verhindert wird, dass alle nachfolgenden Befehle (auch Verzweigungsbefehle, nämlich tund b) ausgeführt werden.

In den zu vereinfachten Beispielen können wir die Ausführung sicher entfernen $!und sedfehlschlagen lassen Nund zurückgeben, da der abgebrochene sBefehl nichts tun würde, wenn er ausgeführt würde, da es keine \nÜbereinstimmung gibt.

Enrico Maria De Angelis
quelle