Ich würde mit Ihnen einverstanden - es wahrscheinlich ist ein allgemeines Problem. Einige gängige Versorgungsunternehmen verfügen jedoch über einige Einrichtungen zur Handhabung.
nl
nl
Trennt z. B. Eingaben in logische Seiten, die -d
durch ein Trennzeichen aus zwei Zeichen voneinander getrennt sind . Drei Vorkommen in einer Zeile geben den Anfang einer Überschrift an , zwei den Hauptteil und eines die Fußzeile . Es ersetzt alle in der Eingabe gefundenen Zeilen durch eine Leerzeile in der Ausgabe. Dies sind die einzigen Leerzeilen, die jemals gedruckt werden
Ich habe Ihr Beispiel so geändert, dass es einen weiteren Abschnitt enthält und ihn einfügt ./infile
. So sieht es also aus:
line A
line B
@@inline-code-start
line X
line Y
line Z
@@inline-code-end
line C
line D
@@start
line M
line N
line O
@@end
Dann habe ich folgendes ausgeführt:
sed 's/^@@.*start$/@@@@@@/
s/^@@.*end$/@@/' <infile |
nl -d@@ -ha -bn -w1
nl
Es kann festgelegt werden, dass der Status auf mehreren logischen Seiten akkumuliert werden soll, dies ist jedoch nicht die Standardeinstellung. Stattdessen werden die Zeilen der Eingabe nach Stilen und nach Abschnitten nummeriert . So -ha
bedeutet die Anzahl alle Kopfzeilen und -bn
bedeutet keine Körperlinien - wie es in einem beginnt Körper Zustand.
Bis ich das gelernt habe, habe ich es nl
für jede Eingabe verwendet, aber nachdem ich gemerkt habe , dass dies nl
die Ausgabe gemäß dem Standard- -d
Elimiter verzerren könnte, habe \:
ich gelernt, vorsichtiger damit umzugehen und habe grep -nF ''
stattdessen begonnen, es für nicht getestete Eingaben zu verwenden. Aber eine andere Lektion, nl
die wir an diesem Tag gelernt haben, war, dass man sie in anderer Hinsicht sehr nützlich anwenden kann - so wie diese - wenn man ihre Eingabe nur geringfügig ändert - wie ich es sed
oben beschrieben habe.
AUSGABE
line A
line B
1 line X
2 line Y
3 line Z
line C
line D
1 line M
2 line N
3 line O
Hier ist noch etwas mehr über nl
- merkt man oben, wie alle Zeilen außer den nummerierten mit Leerzeichen beginnen? Bei nl
Zahlenzeilen wird jeweils eine bestimmte Anzahl von Zeichen in den Kopf eingefügt. Für diese Zeilen wird keine Nummer angegeben - auch keine Leerzeichen - und der Einzug wird immer durch Einfügen von ( -w
idth count + -s
eparator len) * Leerzeichen am Anfang von nicht nummerierten Zeilen erreicht. So können Sie den nicht nummerierten Inhalt exakt reproduzieren, indem Sie ihn mit dem nummerierten Inhalt vergleichen - und das mit geringem Aufwand. Wenn Sie bedenken, dass nl
die Eingabe für Sie in logische Abschnitte unterteilt wird und dass Sie beliebige -s
Zeichenfolgen am Anfang jeder Zeile einfügen können, wird es ziemlich einfach, mit der Ausgabe umzugehen:
sed 's/^@@.*start$/@@@@@@/
s/^@@.*end/@@/; t
s/^\(@@\)\{1,3\}$/& /' <infile |
nl -d@@ -ha -bn -s' do something with the next line!
'
Die oben genannten Drucke ...
line A
line B
1 do something with the next line!
line X
2 do something with the next line!
line Y
3 do something with the next line!
line Z
line C
line D
1 do something with the next line!
line M
2 do something with the next line!
line N
3 do something with the next line!
line O
GNU sed
Wenn dies nl
nicht Ihre Zielanwendung ist, kann eine GNU sed
je nach e
Übereinstimmung einen beliebigen Shell-Befehl für Sie ausführen.
sed '/^@@.*start$/!b
s//nl <<\\@@/;:l;N
s/\(\n@@\)[^\n]*end$/\1/
Tl;e' <infile
Oben sed
sammelt Eingaben im Musterraum, bis genug vorhanden ist, um die Substitution erfolgreich zu bestehen T
und die b
Ranch zurück zum :l
Abel zu beenden . Wenn es der Fall ist, es e
xecutes nl
mit Eingang als dargestellt <<
hier-Dokument für alle den Rest seines Musterraum.
Der Workflow sieht folgendermaßen aus:
/^@@.*start$/!b
- wenn eine
^
ganze Zeile $
ist !
nicht /
entspricht /
das obige Muster, dann wird es b
von dem Skript ranched und autoprinted - so von diesem Zeitpunkt an sind wir nur mit einer Reihe von Linien arbeiten , die mit dem Muster begannen.
s//nl <<\\@@/
- Das leere
s//
Feld /
steht für die letzte Adresse sed
, für die eine Übereinstimmung versucht wurde. Dieser Befehl ersetzt stattdessen die gesamte @@.*start
Zeile nl <<\\@@
.
:l;N
- Der
:
Befehl definiert eine Verzweigungsbezeichnung - hier habe ich eine mit dem Namen :l
abel festgelegt. Mit dem N
Befehl ext wird die nächste Eingabezeile an den Musterbereich \n
angehängt, gefolgt von einem ewline-Zeichen. Dies ist eine der wenigen Möglichkeiten, eine \n
ewline in einem sed
Musterraum zu erhalten - das \n
ewline-Zeichen ist ein sicheres Trennzeichen für einen derer, der es eine sed
Weile getan hat.
s/\(\n@@\)[^\n]*end$/\1/
- diese
s///
ubstitution kann nur erfolgreich sein , nachdem ein Start angetroffen wird und nur auf dem ersten eines nach dem Auftreten Ende Linie. Es wird nur auf einen Musterbereich \n
eingewirkt, in dem unmittelbar nach der letzten ewline @@.*end
das Ende $
des Musterbereichs markiert wird. Wenn es handelt, ersetzt es die gesamte übereinstimmende Zeichenfolge durch die \1
erste \(
Gruppe \)
oder \n@@
.
Tl
- Der
T
Befehl est verzweigt zu einer Bezeichnung (falls angegeben), wenn seit dem letzten Ziehen einer Eingabezeile in den Musterbereich keine erfolgreiche Ersetzung erfolgt ist (wie bei w / N
) . Dies bedeutet, dass jedes Mal, wenn eine \n
ewline an einen Musterbereich angehängt wird, der nicht mit Ihrem Endbegrenzer übereinstimmt, der T
Befehl est fehlschlägt und zurück zum :l
Abel verzweigt , was dazu führt sed
, dass die N
ext-Zeile eingezogen und eine Schleife ausgeführt wird, bis sie erfolgreich ist.
e
Wenn die Ersetzung für die Endübereinstimmung erfolgreich ist und das Skript nicht nach einem fehlgeschlagenen T
est verzweigt , sed
wird e
ein Befehl ausgeführt, der l
wie folgt aussieht :
nl <<\\@@\nline X\nline Y\nline Z\n@@$
Sie können sich davon überzeugen, indem Sie die letzte Zeile so bearbeiten, dass sie aussieht Tl;l;e
.
Es druckt:
line A
line B
1 line X
2 line Y
3 line Z
line C
line D
1 line M
2 line N
3 line O
while ... read
Ein letzter Weg, dies zu tun, und vielleicht der einfachste, ist die Verwendung einer while read
Schleife, aber aus gutem Grund. Die Shell (insbesondere eine bash
Shell) ist in der Regel ziemlich miserabel, wenn es darum geht, Eingaben in großen Mengen oder in gleichmäßigen Strömen zu verarbeiten. Dies ist auch sinnvoll - die Shell hat die Aufgabe, Zeichen für Zeichen mit der Eingabe umzugehen und andere Befehle aufzurufen, die die größeren Dinge verarbeiten können.
Aber wichtiger ist über seine Rolle ist es , dass die Schale darf nicht read
allzu viel von der Eingabe - es spezifiziert ist nicht zu puffern Eingang oder Ausgang zu dem Punkt , dass es so viel verbraucht oder Relais nicht genug Zeit , dass die Befehle es Anrufe fehlen links - auf das Byte. So read
eignet sich hervorragend als Eingangstest - auf return
Informationen darüber , ob es eingegeben verbleibende und Sie sollten den nächsten Befehl aufrufen , es zu lesen - aber es ist sonst in der Regel nicht der beste Weg zu gehen.
Hier ist jedoch ein Beispiel, wie man read
und andere Befehle verwenden könnte, um Eingaben synchron zu verarbeiten:
while IFS= read -r line &&
case $line in (@@*start) :;; (*)
printf %s\\n "$line"
sed -un "/^@@.*start$/q;p";;
esac;do sed -un "/^@@.*end$/q;=;p" |
paste -d: - -
done <infile
Das erste, was bei jeder Iteration passiert, ist das read
Ziehen einer Linie. Wenn es erfolgreich ist , bedeutet es die Schleife noch nicht EOF getroffen und so in der case
es entspricht ein Starttrennzeichen des do
Block wird sofort ausgeführt. Ansonsten printf
druckt $line
es aus read
und sed
wird aufgerufen.
sed
wird p
jede Zeile rucken , bis er die Begegnungen Start marker - wenn es q
Eingang ganz UITS. Der -u
Schalter nbuffered ist für GNU erforderlich, sed
da er ansonsten ziemlich gierig puffern kann, andere POSIXs sed
sollten jedoch - je nach Spezifikation - ohne besondere Berücksichtigung funktionieren - solange <infile
es sich um eine reguläre Datei handelt.
Wenn die ersten sed
q
UITS führt der Schale , die den do
Block der Schleife - das eine andere Anrufe , sed
die jede Zeile druckt , bis er die Begegnungen Ende Marker. Es leitet seine Ausgabe an weiter paste
, da es Zeilennummern jeweils in einer eigenen Zeile ausgibt . So was:
1
line M
2
line N
3
line O
paste
Fügt diese dann zu :
Zeichen zusammen, und die gesamte Ausgabe sieht wie folgt aus:
line A
line B
1:line X
2:line Y
3:line Z
line C
line D
1:line M
2:line N
3:line O
Dies sind nur Beispiele - alles kann entweder im Test oder in den do-Blöcken hier getan werden, aber das erste Dienstprogramm darf nicht zu viel Eingabe verbrauchen.
Alle beteiligten Versorgungsunternehmen lesen dieselbe Eingabe - und drucken ihre Ergebnisse aus - jeweils für sich. Diese Art der Sache kann schwierig sein , den Dreh zu bekommen - weil verschiedene Dienstprogramme mehr als andere puffert - aber Sie können in der Regel verlassen sich auf dd
, head
und sed
das Richtige zu tun (obwohl, für GNU sed
, können Sie die cli-Schalter benötigen) und Darauf sollten Sie sich immer verlassen können read
- denn es ist von Natur aus sehr langsam . Aus diesem Grund wird es in der obigen Schleife nur einmal pro Eingabeblock aufgerufen.
nl
muss nicht Zustand akkumulieren . Schauen Sie sichnl -d
und überprüfen Sie Ihreman
/info
Seiten Informationen übernl
‚s Abschnitt Trennzeichen .