Ich möchte nur die ersten k
Instanzen eines Wortes ersetzen .
Wie kann ich das machen?
Z.B. Angenommen, die Datei foo.txt
enthält 100 Instanzen des Wortes "Linux".
Ich muss nur die ersten 50 Vorkommen ersetzen.
text-processing
sed
awk
Narendra-Choudhary
quelle
quelle
Antworten:
Der erste Abschnitt beschreibt,
sed
wie Sie die ersten k-Vorkommen in einer Zeile ändern. Der zweite Abschnitt erweitert diesen Ansatz, um nur die ersten k-Vorkommen in einer Datei zu ändern, unabhängig davon, in welcher Zeile sie erscheinen.Linienorientierte Lösung
Mit standard sed gibt es einen Befehl, um das k-te Vorkommen eines Wortes in einer Zeile zu ersetzen. Wenn
k
3 ist, zum Beispiel:Oder man kann alle Vorkommen ersetzen durch:
Beides ist nicht das, was Sie wollen.
GNU
sed
bietet eine Erweiterung, die das k-te Vorkommen und alles danach ändert. Wenn k 3 ist, zum Beispiel:Diese können kombiniert werden, um das zu tun, was Sie wollen. So ändern Sie die ersten 3 Vorkommen:
Wo
\n
ist hier nützlich, weil wir sicher sein können, dass es nie in einer Zeile auftritt.Erläuterung:
Wir verwenden drei
sed
Substitutionsbefehle:s/\<old\>/\n/g4
Dies ist die GNU-Erweiterung, um das vierte und alle nachfolgenden Vorkommen von
old
mit zu ersetzen\n
.Die erweiterte Regex-Funktion
\<
wird verwendet, um den Wortanfang und\>
das Wortende abzugleichen. Dies stellt sicher, dass nur vollständige Wörter gefunden werden. Erweiterte reguläre Ausdrücke erfordern die-E
Option zused
.s/\<old\>/new/g
Es
old
bleiben nur die ersten drei Vorkommen von übrig, und dies ersetzt sie alle durchnew
.s/\n/old/g
Das vierte und alle übrigen Vorkommen von
old
wurden\n
im ersten Schritt durch ersetzt. Dies bringt sie in ihren ursprünglichen Zustand zurück.Nicht-GNU-Lösung
Wenn GNU sed nicht verfügbar ist und Sie die ersten drei Vorkommen von
old
to ändern möchtennew
, verwenden Sie dreis
Befehle:Dies funktioniert gut, wenn
k
es sich um eine kleine Zahl handelt, die jedoch schlecht bis groß skaliertk
.Da einige Nicht-GNU-Seds das Kombinieren von Befehlen mit Semikolons nicht unterstützen, wird hier jeder Befehl mit einer eigenen
-e
Option eingeführt. Es kann auch erforderlich sein, zu überprüfen, ob Ihrsed
die Wortbegrenzungssymbole\<
und unterstützt\>
.Dateiorientierte Lösung
Wir können sed anweisen, die gesamte Datei einzulesen und dann die Ersetzungen vorzunehmen. Um zum Beispiel die ersten drei Vorkommen
old
einer BSD-artigen sed zu ersetzen :Die sed-Befehle
H;1h;$!d;x
lesen die gesamte Datei ein.Da die oben genannten keine GNU-Erweiterung verwenden, sollte es auf BSD (OSX) sed funktionieren. Beachten Sie, dass dieser Ansatz ein erfordert
sed
, das lange Zeilen verarbeiten kann. GNUsed
sollte in Ordnung sein. Wer eine Nicht-GNU-Version von verwendet,sed
sollte seine Fähigkeit testen, lange Leitungen zu handhaben.Mit einem GNU-Sed können wir den
g
oben beschriebenen Trick weiter verwenden , aber durch\n
ersetzt\x00
, um die ersten drei Vorkommen zu ersetzen:Dieser Ansatz skaliert gut und
k
wird groß. Dies setzt jedoch voraus, dass dies\x00
nicht in Ihrer ursprünglichen Zeichenfolge enthalten ist. Da es unmöglich ist, das Zeichen\x00
in eine Bash-Zeichenfolge einzufügen, ist dies normalerweise eine sichere Annahme.quelle
tr '\n' '|' < input_file | sed …
. Aber das wandelt natürlich die gesamte Eingabe in eine Zeile um, und einige Nicht-GNU-Seds können nicht mit beliebig langen Zeilen umgehen. (2) Sie sagen: „… oben sollte die in Anführungszeichen stehende Zeichenfolge'|'
durch ein beliebiges Zeichen oder eine Zeichenfolge ersetzt werden.“ Sie können jedoch keintr
Zeichen durch eine Zeichenfolge (mit einer Länge> 1) ersetzen. (3) In Ihrem letzten Beispiel sagen Sie-e 's/\<old\>/new/' -e 's/\<old\>/w/' | tr '\000' '\n'\>/new
. Dies scheint ein Tippfehler für zu sein-e 's/\<old\>/new/' -e 's/\<old\>/new/' -e 's/\<old\>/new/' | tr '\000' '\n'
.Awk verwenden
Die awk-Befehle können verwendet werden, um die ersten N Vorkommen des Wortes durch die Ersetzung zu ersetzen.
Die Befehle werden nur ersetzt, wenn das Wort vollständig übereinstimmt.
In den folgenden Beispielen ersetze ich die ersten
27
Vorkommen vonold
durchnew
Unter Verwendung
Ersetzen Sie das Feld manuell
Führen Sie vorher eine Überprüfung durch
ERGEBNISSE
Z.B
zu
quelle
$i
bisschen vergessen , es wurde bearbeitet, danke :)Angenommen, Sie möchten nur die ersten drei Instanzen einer Zeichenfolge ersetzen ...
Hinweis: Das oben Genannte funktioniert wahrscheinlich nicht mit eingebetteten Kommentaren
... oder in meinem Beispiel mit einer '1' ...
AUSGABE:
Dort verwende ich zwei bemerkenswerte Techniken. Zunächst wird jedes Vorkommen
1
einer Zeile durch ersetzt\n1
. Auf diese Weise kann ich beim nächsten rekursiven Ersetzen sicher sein, dass das Vorkommen nicht zweimal ersetzt wird, wenn meine Ersetzungszeichenfolge meine Ersetzungszeichenfolge enthält. Zum Beispiel, wenn ich ersetzenhe
mithey
ihm wird immer noch funktionieren.Ich mache das wie:
Zweitens zähle ich die Ersetzungen, indem ich
h
bei jedem Auftreten ein Zeichen in das alte Feld einfüge. Sobald ich drei bin, tritt nichts mehr auf. Wenn Sie dies auf Ihre Daten anwenden und\{3\}
die Anzahl der von Ihnen gewünschten Ersetzungen und die/\n1/
Adressen der zu ersetzenden Adressen ändern , sollten Sie nur so viele Ersetzungen vornehmen, wie Sie möchten.Ich habe das ganze
-e
Zeug nur zur besseren Lesbarkeit gemacht. POSIXly Es könnte so geschrieben werden:Und w / GNU
sed
:Denken Sie auch daran, dass dies
sed
zeilenorientiert ist - es liest nicht die gesamte Datei ein und versucht dann, eine Schleife darüber zu erstellen, wie dies in anderen Editoren häufig der Fall ist.sed
ist einfach und effizient. Trotzdem ist es oft praktisch, Folgendes zu tun:Hier ist eine kleine Shell-Funktion, die sie zu einem einfach ausgeführten Befehl zusammenfasst:
Also damit kann ich machen:
...und bekomme...
...oder...
...bekommen...
... oder, um Ihrem Beispiel zu entsprechen (in einer kleineren Größenordnung) :
quelle
Eine kurze Alternative in Perl:
Ändern Sie den Wert von `$ n $ nach Ihren Wünschen.
Wie es funktioniert:
new
fürold
(s/old/new/
) und wann immer sie kann, erhöht er die Variable$i
(++$i
).1 while ...
so lange an der Zeile ( ), wie es$n
insgesamt weniger als Ersetzungen vorgenommen hat, und es kann in dieser Zeile mindestens eine Ersetzung vornehmen.quelle
Verwenden Sie eine Muschelschlaufe und
ex
!Ja, es ist ein bisschen doof.
;)
Hinweis: Dies kann fehlschlagen, wenn
old
die Datei weniger als 50 Instanzen von enthält. (Ich habe es nicht getestet.) In diesem Fall würde die Datei unverändert bleiben.Besser noch, benutze Vim.
Erläuterung:
quelle
Eine einfache, aber nicht sehr schnelle Lösung besteht darin, die in /programming/148451/how-to-use-sed-to-replace-only-the-irst-occurrence-in-a beschriebenen Befehle zu durchlaufen -Datei
Dieser spezielle sed Befehl funktioniert wahrscheinlich nur für GNU sed und wenn newword nicht Teil von oldword ist . Für Nicht-GNU-Benutzer siehe hier, wie nur das erste Muster in einer Datei ersetzt wird.
quelle
Mit GNU können
awk
Sie das DatensatztrennzeichenRS
auf das Wort setzen, das durch Wortgrenzen getrennt werden soll. In diesem Fall wird das Datensatztrennzeichen in der Ausgabe auf das Ersatzwort für die erstenk
Datensätze gesetzt, während das ursprüngliche Datensatztrennzeichen für den Rest beibehalten wirdODER
quelle