僅當特定單字後未設定行時如何附加行

僅當特定單字後未設定行時如何附加行

我建立了以下 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,逐行連接和反轉檔案。 U&L 上的幾個問答中介紹瞭如何使用其他/標準工具反轉文件(例如,指令 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/As 對此進行了大量介紹;例如:如何使用 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)。

相關內容