Aus irgendeinem Grund kann ich keine eindeutige Antwort darauf finden und bin im Moment in einer Zeitkrise. Wie würde ich vorgehen, um eine ausgewählte Textzeile nach der ersten Zeile einzufügen, die mit dem sed
Befehl einer bestimmten Zeichenfolge entspricht? Ich habe ...
CLIENTSCRIPT="foo"
CLIENTFILE="bar"
Und ich möchte eine Zeile nach der CLIENTSCRIPT=
Zeile einfügen, die zu ...
CLIENTSCRIPT="foo"
CLIENTSCRIPT2="hello"
CLIENTFILE="bar"
sed
. Dies ist keine Standardsyntaxsed
und funktioniert mit keiner anderensed
Implementierung.Beachten Sie den Standard
sed
(wie in POSIX, die von allen konformensed
Implementierungen (GNU, OS / X, BSD, Solaris ...) unterstützt wird):Oder in einer Zeile:
(
-e
xpressions (und der Inhalt von-f
iles) werden mit Zeilenumbrüchen verbunden, um die sed-Skriptinterpretationen zu bildensed
).Die
-i
Option für die direkte Bearbeitung ist auch eine GNU-Erweiterung, einige andere Implementierungen (wie die von FreeBSD) unterstützen dies-i ''
.Alternativ können Sie aus Gründen der Portabilität verwenden
perl
stattdessen :Oder Sie könnten verwenden
ed
oderex
:quelle
sed -e '/CLIENTSCRIPT=/a\' -e 'CLIENTSCRIPT2="hello"' file
entgeht dem Anführungszeichen am Ende des ersten Parameters und bricht den Befehl.csh
oder derrc
Familie'...'
sind starke Zitate, in denen Backslash nichts Besonderes ist. Die einzige Ausnahme, die ich kenne, ist diefish
Shell.sed
nicht POSIX-kompatibel ist. Das macht meine Aussage darüber, dass es portabel ist, falsch (für die einzeilige Variante). Ich werde die offene Gruppe um Bestätigung bitten, wenn es sich tatsächlich um eine Nichtkonformität oder eine Fehlinterpretation des Standards meinerseits handelt.Eine POSIX-kompatible Datei mit dem folgenden
s
Befehl:quelle
sed -e '/.../s/$/\' -e 'CLI.../'
was Probleme mit Zeilen vermeiden würde, die Byte-Sequenzen enthalten, die keine gültigen Zeichen bilden.Sed-Befehl, der unter MacOS (mindestens OS 10) und Unix gleichermaßen funktioniert (dh erfordert keine Gnu-Sed wie Gilles (derzeit akzeptiert)):
Dies funktioniert in Bash und möglicherweise auch in anderen Shells, die den $ '\ n' Bewertungszitatstil kennen. Alles kann in einer Zeile stehen und in älteren / POSIX sed-Befehlen funktionieren. Wenn möglicherweise mehrere Zeilen mit CLIENTSCRIPT = "foo" (oder Ihrem Äquivalent) übereinstimmen und Sie die zusätzliche Zeile nur beim ersten Mal hinzufügen möchten, können Sie sie wie folgt überarbeiten:
(Dies erzeugt eine Schleife nach dem Zeileneinfügungscode, die nur den Rest der Datei durchläuft und nie wieder zum ersten sed-Befehl zurückkehrt.)
Möglicherweise stellen Sie fest, dass ich dem übereinstimmenden Muster ein '^ *' hinzugefügt habe, falls diese Zeile beispielsweise in einem Kommentar angezeigt oder eingerückt wird. Es ist nicht 100% perfekt, deckt aber einige andere Situationen ab, die wahrscheinlich häufig sind. Nach Bedarf anpassen ...
Diese beiden Lösungen umgehen auch das Problem (für die generische Lösung zum Hinzufügen einer Zeile), dass, wenn Ihre neu eingefügte Zeile nicht gekapselte Backslashes oder kaufmännisches Und enthält, diese von sed interpretiert werden und wahrscheinlich nicht gleich herauskommen, genau wie die
\n
is - z.\0
wäre die erste übereinstimmende Zeile. Besonders praktisch, wenn Sie eine Zeile hinzufügen, die aus einer Variablen stammt, in der Sie sonst alles zuerst mit $ {var //} oder einer anderen sed-Anweisung usw. maskieren müssten.Diese Lösung ist in Skripten etwas weniger chaotisch (das Zitieren und \ n ist jedoch nicht einfach zu lesen), wenn Sie den Ersatztext für den Befehl a nicht am Anfang einer Zeile einfügen möchten, wenn Sie beispielsweise in einer Funktion stehen mit eingerückten Linien. Ich habe ausgenutzt, dass $ '\ n' von der Shell als Zeilenumbruch ausgewertet wird, nicht in regulären '\ n' Werten in einfachen Anführungszeichen.
Es wird jedoch lang genug, dass ich denke, Perl / sogar Awk könnte gewinnen, weil es besser lesbar ist.
quelle
s/CLIENTSCRIPT="foo"/&\
[Enter]CLIENTSCRIPT2="hello"/
. Der Backslash muss das allerletzte Zeichen in der Zeile sein (kein Leerzeichen danach), anders als es in diesem Kommentar aussieht.s///
sowie in den Befehlena
undi
können mit der gleichen Methode, die ich in meinem obigen Kommentar beschrieben habe, " maskiert " werden.Vielleicht etwas spät, um eine Antwort darauf zu veröffentlichen, aber ich fand einige der oben genannten Lösungen etwas umständlich.
Ich habe versucht, einen einfachen Saitenwechsel in sed durchzuführen, und es hat funktioniert:
& Zeichen spiegelt die übereinstimmende Zeichenfolge wider. Anschließend fügen Sie \ n und die neue Zeile hinzu.
Wie bereits erwähnt, wenn Sie dies vor Ort tun möchten:
Etwas anderes. Sie können mit einem Ausdruck übereinstimmen:
Hoffe das hilft jemandem
quelle
\n
in der Ersatzzeichenfolge verstanden wird. Plain-Vanilla (POSIX)sed
ist nicht verstehen\n
in der Ersatzzeichenfolge jedoch so das wird nicht funktionieren auf BSD oder macOS-es sei denn , Sie haben installiert GNU irgendwie sed. Mit Vanille sed Sie können Zeilenumbrüche durch „Flucht“ sie das einzubetten, ist die Zeile mit einem Backslash, dann drücken Sie [Enter] ( Referenz , unter der Überschrift[2addr]s/BRE/replacement/flags
). Dies bedeutet, dass Ihr sed-Befehl mehrere Zeilen im Terminal umfassen muss.Die awk-Variante:
quelle
1;
Sie Warum druckt "1" in awk die aktuelle Zeile?Ich hatte eine ähnliche Aufgabe und konnte die oben genannte Perl-Lösung nicht zum Laufen bringen.
Hier ist meine Lösung:
perl -i -pe "BEGIN{undef $/;} s/^\[mysqld\]$/[mysqld]\n\ncollation-server = utf8_unicode_ci\n/sgm" /etc/mysql/my.cnf
Erläuterung:
Verwendet einen regulären Ausdruck, um in meiner Datei /etc/mysql/my.cnf nach einer Zeile zu suchen, die nur diese enthält
[mysqld]
und durch diese ersetzt[mysqld] collation-server = utf8_unicode_ci
effektiv die
collation-server = utf8_unicode_ci
Zeile nach der Zeile hinzufügen, die enthält[mysqld]
.quelle
Ich musste dies kürzlich auch für Mac- und Linux-Betriebssysteme tun. Nachdem ich viele Beiträge durchgesehen und viele Dinge ausprobiert hatte, kam ich meiner Meinung nach nie dahin, wo ich wollte, nämlich: eine einfach genug zu verstehende Lösung mit bekannten und Standardbefehle mit einfachen Mustern, einzeilig, tragbar, erweiterbar, um weitere Einschränkungen hinzuzufügen. Dann habe ich versucht, es aus einer anderen Perspektive zu betrachten. Dann wurde mir klar, dass ich auf die Option "Einzeiler" verzichten kann, wenn ein "Zweiliner" den Rest meiner Kriterien erfüllt. Am Ende habe ich mir diese Lösung ausgedacht, die sowohl unter Ubuntu als auch unter Mac funktioniert und die ich mit allen teilen wollte:
Im ersten Befehl sucht grep nach Zeilennummern, die "foo" enthalten, cut / head wählt das erste Vorkommen aus, und die arithmetische Operation erhöht die Zeilennummer des ersten Vorkommens um 1, da ich sie nach dem Vorkommen einfügen möchte. Im zweiten Befehl handelt es sich um eine direkte Dateibearbeitung, "i" zum Einfügen: eine Antwort, die eine neue Zeile, "bar" und dann eine weitere neue Zeile zitiert. Das Ergebnis ist das Hinzufügen einer neuen Zeile mit "bar" nach der Zeile "foo". Jeder dieser beiden Befehle kann auf komplexere Operationen und Übereinstimmungen erweitert werden.
quelle