我建立了以下 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
)。