特定の単語の後に行が設定されていない場合にのみ行を追加する方法

特定の単語の後に行が設定されていない場合にのみ行を追加する方法

次の行を追加するために、次のsed cliを構築しました。

force_https_protocol=PROTOCOL_TLSv1_2

ラインの後ろ:

[security]

sed コマンドラインインタフェース:

sed  -i '/\[security\]/a force_https_protocol=PROTOCOL_TLSv1_2'  /etc/ambari-agent/conf/ambari-agent.ini

しかし、問題は - 行がforce_https_protocol=PROTOCOL_TLSv1_2 すでに後ろにあるときです。[security]

すでに存在する場合は、行の追加を無視するようにsed構文をどのように変更できますか?

期待される出力

[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
force_https_protocol=PROTOCOL_TLSv1_2
keysdir=/var/lib/ambari-agent/keys
server_crt=ca.crt
passphrase_env_var_name=AMBARI_PASSPHRASE

答え1

ファイル内のすべての「force_https_protocol=PROTOCOL_TLSv1_2」が[security]タグ内にあり、他の場所には表示されないとします。

sed -e '/^force_https_protocol=PROTOCOL_TLSv1_2$/d'\
    -e '/\[security\]/a force_https_protocol=PROTOCOL_TLSv1_2' file

アイデアは、文字列 "force_https_protocol=PROTOCOL_TLSv1_2"のみを含むファイルのすべての行を削除することです。

説明する

/^force_https_protocol=PROTOCOL_TLSv1_2$/d'

"force_https_protocol=PROTOCOL_TLSv1_2" 文字列を含むすべての行を削除します。

テスト

$ 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

答え2

1. AWKを使用

より一般的な問題を追加する可能な解決策は次のとおりです。ひも場合のみひもまだ表示されていません。

簡単なアプローチは、ファイルを後ろに移動して、最後に発生した時点を追跡することです。ひも、特定のラベルが表示されるたびに(ラベル自体を印刷する直前)印刷するが、まだ見たことがない場合にのみ(ひも)しかし遭遇するのを忘れてください(ひも)タグに会うたびに。もちろん、最後のステップは結果を反転することです。

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、含まれるGNU Coreutils、ファイルを 1 行ずつリンクし、逆方向にします。 U&Lの複数のQ&Aでは、ギター/標準ツール(例:コマンド sed '1!G;h;$!d' ファイルの内容をどのように戻しますか?そしてリバースのインポート)。

force_https_protocol=PROTOCOL_TLSv1_2次のテキストスニペットの最初の部分の後には挿入されません。[security]

[security]
keysdir=/var/lib/ambari-agent/keys
force_https_protocol=PROTOCOL_TLSv1_2
passphrase_env_var_name=AMBARI_PASSPHRASE

[security]
...

ただ挿入してくださいひもラベルが表示されるたびにひもすでに存在しているのと同じアプローチで、次のことが発生する可能性があります。

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

(これ〜する上記のテキストの例の後に挿入してくださいforce_https_protocol=PROTOCOL_TLSv1_2。)[security]

2. sedを使う

sedさまざまなループが利用可能です(N;P;D;U&Lの他のQ / Aでこれを広く扱っています。例:sedを使用して複数行の文字列を置き換える方法は?またはsedを使用してパターンの後の次の行を編集するには?)。

その行は、前の行がまだ存在しない場合force_https_protocol=PROTOCOL_TLSv1_2にのみ構成された行の後に挿入されます。[security]

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/'

このスクリプトは次のとおりです。

  • 最後の行()を除く各行に、改行文字$!と次の行をパターンスペース(N)(現在の行が含まれている)に追加します。
  • Pその行が次の場合は、パターンスペース()の最初の行を印刷します[security]
    • ...次の行はですforce_https_protocol=PROTOCOL_TLSv1_2。パターンスペースから最初の行を削除して新しいループ(b b、、:b D)を開始します。
    • それ以外の場合は、パターンスペースから最初の行を削除し、新しいループを開始する前にforce_https_protocol=PROTOCOL_TLSv1_2標準出力()として印刷します()。i\D
  • 最後の行がある場合は[security]、その行をそれ自体に置き換え、その後に改行を追加してforce_https_protocol=PROTOCOL_TLSv1_2結果を印刷します(暗黙的にp)。

関連情報