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
nlTrennt z. B. Eingaben in logische Seiten, die -ddurch 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
nlEs 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 -habedeutet die Anzahl alle Kopfzeilen und -bnbedeutet keine Körperlinien - wie es in einem beginnt Körper Zustand.
Bis ich das gelernt habe, habe ich es nlfür jede Eingabe verwendet, aber nachdem ich gemerkt habe , dass dies nldie Ausgabe gemäß dem Standard- -dElimiter 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, nldie 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 sedoben 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 nlZahlenzeilen 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 ( -width count + -separator 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 nldie Eingabe für Sie in logische Abschnitte unterteilt wird und dass Sie beliebige -sZeichenfolgen 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 nlnicht Ihre Zielanwendung ist, kann eine GNU sedje 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 sedsammelt Eingaben im Musterraum, bis genug vorhanden ist, um die Substitution erfolgreich zu bestehen Tund die bRanch zurück zum :lAbel zu beenden . Wenn es der Fall ist, es executes nlmit 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 bvon 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 @@.*startZeile nl <<\\@@.
:l;N
- Der
:Befehl definiert eine Verzweigungsbezeichnung - hier habe ich eine mit dem Namen :label festgelegt. Mit dem NBefehl ext wird die nächste Eingabezeile an den Musterbereich \nangehängt, gefolgt von einem ewline-Zeichen. Dies ist eine der wenigen Möglichkeiten, eine \newline in einem sedMusterraum zu erhalten - das \newline-Zeichen ist ein sicheres Trennzeichen für einen derer, der es eine sedWeile 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 \neingewirkt, in dem unmittelbar nach der letzten ewline @@.*enddas Ende $des Musterbereichs markiert wird. Wenn es handelt, ersetzt es die gesamte übereinstimmende Zeichenfolge durch die \1erste \(Gruppe \)oder \n@@.
Tl
- Der
TBefehl 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 \newline an einen Musterbereich angehängt wird, der nicht mit Ihrem Endbegrenzer übereinstimmt, der TBefehl est fehlschlägt und zurück zum :lAbel verzweigt , was dazu führt sed, dass die Next-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 Test verzweigt , sedwird eein Befehl ausgeführt, der lwie 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 readSchleife, aber aus gutem Grund. Die Shell (insbesondere eine bashShell) 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 readeignet sich hervorragend als Eingangstest - auf returnInformationen 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 readZiehen einer Linie. Wenn es erfolgreich ist , bedeutet es die Schleife noch nicht EOF getroffen und so in der casees entspricht ein Starttrennzeichen des doBlock wird sofort ausgeführt. Ansonsten printfdruckt $linees aus readund sedwird aufgerufen.
sedwird pjede Zeile rucken , bis er die Begegnungen Start marker - wenn es qEingang ganz UITS. Der -uSchalter nbuffered ist für GNU erforderlich, sedda er ansonsten ziemlich gierig puffern kann, andere POSIXs sedsollten jedoch - je nach Spezifikation - ohne besondere Berücksichtigung funktionieren - solange <infilees sich um eine reguläre Datei handelt.
Wenn die ersten sed qUITS führt der Schale , die den doBlock der Schleife - das eine andere Anrufe , seddie 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
pasteFü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, headund seddas 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.
nlmuss nicht Zustand akkumulieren . Schauen Sie sichnl -dund überprüfen Sie Ihreman/infoSeiten Informationen übernl‚s Abschnitt Trennzeichen .