Ich baue das folgende Sed-CLI, um die folgende Zeile hinzuzufügen
force_https_protocol=PROTOCOL_TLSv1_2
nach der Zeile:
[security]
die Sed-CLI:
sed -i '/\[security\]/a force_https_protocol=PROTOCOL_TLSv1_2' /etc/ambari-agent/conf/ambari-agent.ini
aber das Problem ist, wenn die Zeile - force_https_protocol=PROTOCOL_TLSv1_2
bereits nach[security]
wie kann die Sed-Syntax geändert werden, um das Hinzufügen der Zeile zu ignorieren, wenn die Zeile bereits vorhanden ist?
erwartete Ausgabe
[security]
force_https_protocol=PROTOCOL_TLSv1_2
keysdir=/var/lib/ambari-agent/keys
server_crt=ca.crt
passphrase_env_var_name=AMBARI_PASSPHRASE
falsche Datei:
[security]
force_https_protocol=PROTOCOL_TLSv1_2
force_https_protocol=PROTOCOL_TLSv1_2
keysdir=/var/lib/ambari-agent/keys
server_crt=ca.crt
passphrase_env_var_name=AMBARI_PASSPHRASE
Antwort1
Vorausgesetzt, dass alle "force_https_protocol=PROTOCOL_TLSv1_2" in der Datei innerhalb des Tags [security] stehen und nicht anderswo auftauchen
sed -e '/^force_https_protocol=PROTOCOL_TLSv1_2$/d'\
-e '/\[security\]/a force_https_protocol=PROTOCOL_TLSv1_2' file
Die Idee besteht darin, alle Zeilen in der Datei zu löschen, die (nur) die Zeichenfolge „force_https_protocol=PROTOCOL_TLSv1_2“ enthalten.
Erläuterung
/^force_https_protocol=PROTOCOL_TLSv1_2$/d'
Löschen Sie alle Zeilen, die die Zeichenfolge „force_https_protocol=PROTOCOL_TLSv1_2“ enthalten.
Tests
$ cat file
[security]
force_https_protocol=PROTOCOL_TLSv1_2
keysdir=/var/lib/ambari-agent/keys
server_crt=ca.crt
passphrase_env_var_name=AMBARI_PASSPHRASE
[security]
keysdir=/var/lib/ambari-agent/keys
server_crt=ca.crt
passphrase_env_var_name=AMBARI_PASSPHRASE
$ sed -e '/^force_https_protocol=PROTOCOL_TLSv1_2$/d'\
-e '/\[security\]/a force_https_protocol=PROTOCOL_TLSv1_2' file
[security]
force_https_protocol=PROTOCOL_TLSv1_2
keysdir=/var/lib/ambari-agent/keys
server_crt=ca.crt
passphrase_env_var_name=AMBARI_PASSPHRASE
[security]
force_https_protocol=PROTOCOL_TLSv1_2
keysdir=/var/lib/ambari-agent/keys
server_crt=ca.crt
passphrase_env_var_name=AMBARI_PASSPHRASE
Antwort2
1. Verwendung von AWK
Hier ist eine mögliche Lösung für das allgemeinere Problem des Hinzufügens einesSchnurauf einen beschrifteten Textblock (also die Textzeilen, die in einer Datei auf eine bestimmte Beschriftung folgen und der nächsten Beschriftung oder der zweiten Beschriftung der Datei vorangehen) nur dann, wennSchnurist noch nicht vorhanden.
Ein einfacher Ansatz besteht darin, die Datei rückwärts durchzugehen und den letzten Zeitpunkt zu verfolgen, an dem wirSchnur, drucken Sie es jedes Mal aus, wenn wir auf ein bestimmtes Etikett stoßen (direkt vor dem Drucken des Etiketts selbst), aber nur, wenn wir es nicht gesehen haben (Schnur) und vergessen Sie, dass Sie ihm begegnet sind (Schnur), jedes Mal, wenn wir auf ein Etikett stoßen. Und natürlich kehren wir das Ergebnis als letzten Schritt um.
tac file | awk '
/^force_https_protocol=PROTOCOL_TLSv1_2$/ {
seen = 1
}
/^\[security\]$/ {
if ( ! seen ) {
print "force_https_protocol=PROTOCOL_TLSv1_2"
}
}
/^\[[^]]*\]$/ {
seen = 0
}
1' | tac
tac
, enthalten inGNU Coreutils, verknüpft und kehrt Dateien Zeile für Zeile um. Wie man eine Datei mit anderen/Standard-Tools umkehrt, wird in mehreren Fragen und Antworten zu U&L behandelt (zum BeispielWie kehrt der Befehl sed '1!G;h;$!d' den Inhalt einer Datei um?UndUmgekehrtes Greppen).
Dies wird im folgenden Textausschnitt nicht force_https_protocol=PROTOCOL_TLSv1_2
nach dem ersten eingefügt:[security]
[security]
keysdir=/var/lib/ambari-agent/keys
force_https_protocol=PROTOCOL_TLSv1_2
passphrase_env_var_name=AMBARI_PASSPHRASE
[security]
...
Zum einfachen EinfügenSchnurnach jedem Vorkommen eines Labels, es sei dennSchnurist bereits vorhanden, der gleiche Ansatz kann zu Folgendem führen:
tac file | awk '
/^force_https_protocol=PROTOCOL_TLSv1_2$/ {
seen = NR
}
/^\[security\]$/ {
if ( ( NR == 1 ) || ! ( NR == seen + 1 ) ) {
print "force_https_protocol=PROTOCOL_TLSv1_2"
}
}
1' | tac
(DasWilleim obigen Textbeispiel force_https_protocol=PROTOCOL_TLSv1_2
nachher einfügen ).[security]
2. Verwenden von sed
Sie sed
können eine Variante des N;P;D;
Zyklus verwenden (der in anderen Fragen und Antworten zu U&L ausführlich behandelt wird, zum Beispiel:Wie kann ich sed verwenden, um eine mehrzeilige Zeichenfolge zu ersetzen?oderWie bearbeite ich die nächste Zeile nach dem Muster mit sed?).
Dadurch wird die Zeile force_https_protocol=PROTOCOL_TLSv1_2
nach einer Zeile eingefügt, die ausschließlich aus besteht, [security]
nur wenn die vorherige nicht bereits vorhanden ist.
sed '
$! {
N
P
/^\[security\]\n/ {
/\nforce_https_protocol=PROTOCOL_TLSv1_2$/ b b
i\
force_https_protocol=PROTOCOL_TLSv1_2
}
:b
D
}
s/^\[security\]$/&\
force_https_protocol=PROTOCOL_TLSv1_2/'
Dieses Skript:
- für jede Zeile, außer der letzten (
$!
), wird ein Zeilenumbruch gefolgt von der nächsten Zeile an den Musterbereich (N
) angehängt (der bereits die aktuelle Zeile enthält); - druckt die erste Zeile im Musterbereich (
P
); wenn diese Zeile[security]
... ist.- ... und die nächste Zeile ist
force_https_protocol=PROTOCOL_TLSv1_2
, löscht einfach die erste Zeile aus dem Musterbereich und startet einen neuen Zyklus (b b
,:b D
); - andernfalls wird
force_https_protocol=PROTOCOL_TLSv1_2
auf die Standardausgabe (i\
) gedruckt, bevor die erste Zeile aus dem Musterbereich gelöscht und ein neuer Zyklus gestartet wird (D
);
- ... und die nächste Zeile ist
- Wenn die letzte Zeile ist
[security]
, wird sie durch sich selbst ersetzt, gefolgt von einem Zeilenumbruch undforce_https_protocol=PROTOCOL_TLSv1_2
und das Ergebnis wird ausgedruckt (mithilfe des implizitenp
).