Ist es möglich, mehrere bestimmte Zeilennummern (nicht den Bereich) mit sed abzugleichen?


9

Erwägen:

echo -e "a\nb\nc\nd\ne\nf\ng\nh" | sed '3,5a test'

Dies entspricht den Zeilen 3, 4 und 5.

Aber ich versuche nur die Zeilen 3 und 5 (nicht 4) abzugleichen. Und fügen Sie 'Test' nach ihnen hinzu.

Antworten:


9
echo ... | sed -e '3a test' -e '5a test'

Wenn die Operation komplexer ist als in diesem Fall, können Sie eine Struktur wie die folgende verwenden:

sed 'b pattern; : action; a \
lalala
b end; : pattern; 3b action; 5b action; : end'

Dh Sie setzen alle Befehle, die Sie brauchen, zwischen b pattern;und b end;.

Und Sie fügen danach alle Ihre Muster (Zeilennummern oder was auch immer) hinzu : pattern;.

Was passiert ist folgendes:

  1. Der erste Befehl springt über den Aktionsteil (möglicherweise ist es einfacher zu lesen, wenn sich die Muster am Anfang und b end;direkt vor dem Aktionsteil befinden).

  2. Wenn ein Muster übereinstimmt, springt die Ausführung zum Aktionsteil. Nach der Aktion springt die Ausführung des Teils zum Ende.

Ich versuche das aufzuräumen:

sed '3b action; 5b action; b end; : action; a \
lalala
: end'

In einer einzigen Zeile wäre wie:

sed "3b idAction; 5b idAction; b; : idAction; a test"

Portabel müssen Sie es schreiben:

sed '
   3b action
   5b action
   b
   : action
   a\
   lalala'

( bOhne Label-Verzweigungen bis zum Ende, sodass Sie kein explizites endLabel benötigen , ;ist ein Zeichen in einem Label in Standardimplementierungen gültig sed.)


4
Wow, sed Unterprogramme. Cool
— Glenn Jackman

Wow, könnten Sie diese erweitern? Sie sehen wirklich nützlich aus!
— Terdon

der mit 'pattern' und 'action' scheint sehr gut zu sein, da ich 'test' (oder 'lalala') nicht wiederholen muss, muss es aber noch besser verstehen, danke! :)
— Wassermann Power

@terdon Was könnte ich?
— Hauke ​​Laging

Ich meinte, dass der zweite großartig aussieht, aber schwer zu verstehen ist, und wenn Sie die Zeit haben, würde ich mich über eine Erklärung freuen.
— Terdon

5

Mit sed(siehe Antwort von @ HaukeLaging )

Mit awk:

$ echo -e "a\nb\nc\nd\ne\nf\ng\nh" | awk 'NR==3 || NR==5{$0=$0"\ntest"}1;'

Mit perl:

$ echo -e "a\nb\nc\nd\ne\nf\ng\nh" | perl -pe '$_ .="test\n" if $. == 3 || $. == 5'

Kann Ihre Perl ein bisschen Golf spielen, mit dem Operator "Smart Match":perl -lnE 'say if $. ~~ @{[3,5]}'
— Glenn Jackman

@glennjackman ah, ja in der Tat, danke. Ich muss zugeben, dass ich ein bisschen vorsichtig bin ~~, verstehe es nicht so gut, wie ich sollte. Auch beide sayund ~~brauchen Perl v> = 5.10 richtig?
— Terdon

Ich muss 'test' nach diesen Zeilen anhängen, ich sehe jetzt, es wäre besser gewesen, das von Anfang an klargestellt zu haben. Ich habe gerade das OP bearbeitet.
— Wassermann Macht

@AquariusPower, perl -pE 'say "test" if $. ~~ @{[4,6]}'- dies stellt die Zeile voran : Perl -pmacht einen impliziten Druck am Ende des angegebenen Programms.
— Glenn Jackman

@AquariusPower siehe auch aktualisierte Antwort.
— Terdon

3

Wie @HaukeLaging bereits sagte, macht dieser Befehl, was Sie wollen:

sed -e'3a test' -e'5a test'

Die Eingabe kann jetzt ziemlich umständlich werden, wenn Sie beispielsweise 20 Zeilen abgleichen möchten.

In diesen Fällen können Sie stattdessen diesen Befehl verwenden , vorausgesetzt, Ihre Shell unterstützt die Klammererweiterung :

sed -e{3,5}'a test'

(Beachten Sie, dass die geschweiften Klammern und das Komma nicht in Anführungszeichen stehen müssen.)

Infolgedessen übergibt die Shell die Argumente an -e3a testund -e5a testan sed, genau wie der erste Befehl.

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.