it-swarm.com.de

Verwenden von sed zum Bearbeiten eines beliebigen Vorkommens eines übereinstimmenden Musters

Eine Zeile beginnend mit Fred Flintstone soll mit einer Zeichenkette angehängt werden. Suchen Sie nach dem angegebenen Vorkommen von Fred Flintstone und hängen Sie es an.

Wie verwende ich diesen Befehl für eines der Vorkommen eines solchen Musters? Ich habe es versucht

sed '/Fred Flintstone/ s/$/ someString/2' filename

Anscheinend funktioniert das obige nicht. Es funktioniert gut für alle Vorkommen, aber nicht für ein bestimmtes Vorkommen. (Angenommen, ich möchte den ersten oder zweiten oder dritten [einen von ihnen] ersetzen.)

Beispieldatei1:

Fred Flintstone 
Johnson Stone
Fred Flintstone
Fred Flintstone
Michael Clark

Gewünschte Ausgabedatei1:

Fred Flintstone 
Johnson Stone
Fred Flintstone someString
Fred Flintstone
Michael Clark
6
DazzlerJay

Obwohl Sie sed erwähnt haben, handelt es sich hierbei um eine Art von awk -y Aufgaben:

awk -v pat="Fred Flintstone" '$0 ~ pat {count++;\
               if (count == 2) { $0 = $0" someString" ;} ;}; 1' file.txt
  • -v pat="Fred Flintstone" speichert das Regex-Muster als Variable pat, die in awk Ausdrücken verwendet werden soll

  • $0 ~ pat prüft den Datensatz gegen pat auf eine Übereinstimmung; Bei Übereinstimmung wird die Variable count um 1 erhöht, und wenn count 2 ist, wird der Datensatz mit dem aktuellen Inhalt plus someString ({count++; if (count == 2) { $0 = $0" someString" ;} ;}) zurückgesetzt.

  • 1 ist eine Redewendung; Da es wahr ist , werden alle Datensätze gedruckt

Beispiel:

% cat file.txt
Fred Flintstone
Johnson Stone
Fred Flintstone
Fred Flintstone
Michael Clark

% awk -v pat="Fred Flintstone" '$0 ~ pat {count++; if (count == 2) { $0 = $0" someString" ;} ;}; 1' file.txt
Fred Flintstone
Johnson Stone
Fred Flintstone someString
Fred Flintstone
Michael Clark
7
heemayl

Mit diesem einfachen Befehl sed können Sie die Änderung selektiv vornehmen, ohne Schleifen zu verwenden (es wird eine Verzweigung zum Ende verwendet) oder GNU -Erweiterungen zu benötigen oder die gesamte Datei auf einmal zu lesen:

sed -r '/Fred Flintstone/ {x; s/$/#/; /^#{2}$/ {x; s/.*/& someString/; b}; x}'

Erläuterung:

  • -r - Verwenden Sie Extended Regex
  • /Fred Flintstone/ - für Zeilen, die diesem Muster entsprechen:
    • x - Musterplatz austauschen und Platz halten (Zähler aktivieren)
    • s/$/#/ - Fügt dem Zähler ein Zeichen hinzu
    • /^#{2}$/ - wenn der Zähler die Länge 2 hat (einen beliebigen Wert ersetzen)
      • x tausche den Musterraum und halte den Raum (aktiviere die gezählte Eingabezeile)
      • s/.*/& someString/ - Hängt den String an die gewünschte Zeile an
      • b - Zum Ende der Verarbeitung für diese Zeile springen, damit sie gedruckt werden kann
    • x - Vertausche das Muster und halte das Leerzeichen (aktiviere Zeilen, die mit der Zeichenkette übereinstimmen, aber nicht die Anzahl)

Die Einrückungsstufen in der Erläuterung geben die Verschachtelungsstufen für geschweifte Klammern an.

Alle anderen Zeilen werden ohne Bearbeitung durchlaufen und gedruckt.

5

Die Antwort wurde überarbeitet, um das Einfügen von Code in Back-Slashes und Slashes zu verhindern. Anführungszeichen bei Verwendung von awk -Variablen awk -v variable ... oder einer Shell awk '...' variable="$value" seit awk entgeht C der Sequenzverarbeitung für Werte, die mit -v variable= oder Shell variable=$value übergeben wurden; Daher ändert sich der Shell variable='\\n' innerhalb von awk ) zu \n.

pattern="${patt//\\/\\\\}" awk '
    $0 ~ ENVIRON["pattern"]{ seen++ } seen==2 { $0 = $0 "something"};1' infile

für die folgende Eingabe und das Muster :

another break line
Johnson Stone
\"Fred //\\Flintstone' SOMETHING will goes here ...
\"Fred //\\Flintstone'
Michael Clark

muster ist in einer Variablen namens patt

$ echo "$patt"
\"Fred //\\Flintstone'

Die Ausgabe ist:

\"Fred //\\Flintstone'
another break line
Johnson Stone
\"Fred //\\Flintstone' SOMETHING will goes here ...something
\"Fred //\\Flintstone'
Michael Clark

Erläuterung:

später müssen Sie möglicherweise something als Variable übergeben, und Sie müssen etwas wie edit=$somesting verwenden und dort ENVIRON["edit"] verwenden.

pattern="${patt//\\/\\\\}" edit="$something" awk '
    $0 ~ ENVIRON["pattern"]{ seen++ } seen==2 { $0 = $0 ENVIRON["edit"]};1' infile
5
αғsнιη

Hier ist eine Möglichkeit, dies in sed zu tun, ohne die gesamte Datei in den Speicher zu kopieren:

  • finde das erste Vorkommen des Musters
  • fügen Sie die nächste Zeile N an den Musterbereich an
  • versuchen Sie, das zweite Vorkommen des Musters zu ersetzen
  • verzweige zurück und füge eine weitere Zeile hinzu, wenn die Übereinstimmung fehlschlägt Ta

Der $q beendet die Schleife, wenn das Dateiende ohne Übereinstimmung erreicht wird.

Damit

sed '/Fred Flintstone/ {:a; $q; N; s//& someString/2; Ta;}' File1
Fred Flintstone 
Johnson Stone
Fred Flintstone someString
Fred Flintstone
Michael Clark

Obwohl T eine GNU Erweiterung ist, können Sie dies auch in POSIX sed mit t; ba tun.


Hmm ... nach einigem Überlegen wird der neue Text tatsächlich an jedes andere Vorkommen angehängt - nicht nur an das zweite. Wenn Sie wirklich nur das zweite Vorkommen ersetzen müssen, ist die einzige Möglichkeit, die ich mir vorstellen kann, dies zu tun:

  • adressiere und ersetze die erste Instanz durch eine eindeutige Zeichenkette
  • adressieren und ändern Sie die neue erste Instanz
  • adressieren und ersetzen Sie die eindeutige Zeichenfolge durch das ursprüngliche Muster

GNU sed bietet einen Trick, um die erste Instanz eines Musters zu adressieren

0,/pattern/

Damit

sed -e '0,/Fred Flintstone/ s//Barney Rubble/' \
    -e '0,/Fred Flintstone/ s//& someString/' \
    -e '0,/Barney Rubble/ s//Fred Flintstone/
' File1
Fred Flintstone
Johnson Stone
Fred Flintstone someString
Fred Flintstone
Michael Clark

Wenn es Ihnen nichts ausmacht, ed zu verwenden, können Sie die zweite Instanz direkter ansprechen, indem Sie in die erste Zeile gehen und dann von einer Instanz zur nächsten weiterleiten:

ed -s File1 << \EOF                                                                                                              
1;#
/Fred Flintstone/,/Fred Flintstone/ s//& someString/
,p
q
EOF
Fred Flintstone
Johnson Stone
Fred Flintstone someString
Fred Flintstone
Michael Clark

oder als Einzeiler

printf '1;#\n/Fred Flintstone/,/Fred Flintstone/ s//& someString/\n,p\n' | ed -s File1

Sie können die ed-Version an Ort und Stelle setzen, indem Sie ,p durch w ersetzen.

4
steeldriver

Ein weiterer Anwendungsfall für ex, den von POSIX angegebenen Datei-Editor

(Es ist der Vorgänger von vi und ist immer noch ein Teil von vi.)

printf '%s\n' '0/Fred Flintstone///s/$/ someString/' x | ex filename

Die Magie dabei ist, dass ex im Gegensatz zu Sed, Awk und ähnlichen Tools nicht in jeder Zeile Code ausführt. Sie können den Cursor bewegen, Befehle erteilen usw.

In diesem Fall geben wir eine Zeilennummer 0 an (die sicherstellt, dass Fred Flintstone in der ersten Zeile berücksichtigt wird), gefolgt von einer Regex /Fred Flintstone/, die auf die erste Zeile in der Dateizuordnung verweist Dieser reguläre Ausdruck, gefolgt von einem anderen regulären Ausdruck //, der leer ist und den letzten regulären Ausdruck wiederverwendet und so auf die zweite Zeile in der Datei verweist, die Streichhölzer; und dann verwenden wir den Befehl s, den Sie bereits kennen.

Der Befehl x bedeutet, dass alle Änderungen gespeichert und beendet werden.

Wir verwenden printf, um Befehle an ex weiterzuleiten.

2
Wildcard