So fügen Sie eine Zeile nur dann an, wenn nach einem bestimmten Wort keine Zeile gesetzt ist

So fügen Sie eine Zeile nur dann an, wenn nach einem bestimmten Wort keine Zeile gesetzt ist

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_2nach 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_2nachher einfügen ).[security]

2. Verwenden von sed

Sie sedkö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_2nach 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_2auf die Standardausgabe ( i\) gedruckt, bevor die erste Zeile aus dem Musterbereich gelöscht und ein neuer Zyklus gestartet wird ( D);
  • Wenn die letzte Zeile ist [security], wird sie durch sich selbst ersetzt, gefolgt von einem Zeilenumbruch und force_https_protocol=PROTOCOL_TLSv1_2und das Ergebnis wird ausgedruckt (mithilfe des impliziten p).

verwandte Informationen