在兩個匹配行之後替換匹配文本
我有一個 YAML 文件,其中包含一個節,如下所示:
admin::common::passwords: alice: password: '$6$oTQhLvN/4VFJPscD$8LYwUMSFi' bob: password: '$6$JKOtLF0wHeZfIskt$W/M5.ugDS'
如果 shell 變數 $ ACCOUNT contains the account name (alice, bob, etc), and $ YAML 是 YAML 文件的文件名,我可以用 sed 添加一個新條目,像這樣。它將新帳戶直接插入到“admin::common::passwords:”行下,所以我知道它在正確的節中:
sed -i /'^admin::common::passwords:'/a"\ ${ACCOUNT}:\n password: '${ENCRYPTED_PASS}'" $YAML
我可以使用 awk 找到這樣的現有帳戶。同樣,這會找到該節,然後在該節中找到帳戶(這可能都可以在 awk 中完成,但我在 awk 方面還不夠好,這將完成這項工作):
awk "BEGIN{RS=ORS="\n\n";FS=OFS="\n"}/admin::common::passwords:/" $YAML | grep -A1 "^[ ]*${ACCOUNT}:"
但是要刪除一行,我能想到的最好的方法是:
sed -i "/^ ${ACCOUNT}:/,+1d" $YAML
這將刪除文件中任何位置的任何行“^ alice:”,無論它是在 admin::common::passwords 節還是其他地方。
我不能對文件的內容做任何假設,除了它確實包含一個 admin::common:passwords 節(如果沒有,那麼它將由我的腳本的另一部分創建;那一點是簡單的)。
所以,我的問題是:我怎樣才能改進這個 sed 說“在 admin::common::passwords 節中搜尋“^ ${ACCOUNT}:” ,並刪除匹配的行以及它下面的行’ ?
(當然,它不必是 sed;可能是 awk 甚至 Perl 更適合這項任務)
sed " /^admin::common::passwords:$/,/^[^ ].*:$/ { /^ $ACCOUNT:$/ { N;d } }" < "$YAML"
也就是說,將您的刪除節包含在
admin::common...
與 next之間匹配的部分中whatever-section:
。請注意,
.
使用者名中常見的字元也是正則表達式運算符,因此john.doe
可以匹配john.doe
但也可以匹配johnWdoe
。
admin::common::passwords
請注意,如果您有兩個連續的部分並且要刪除的帳戶在第二個中,則上述方法將不起作用。如果,正如 Otheus 所指出的那樣,部分執行到具有相同或更少前導空格字元的下一行,並且您的
admin::common::passwords:
部分可能有一些前導空格,那麼可能是時候切換到另一種語言,例如awk
:awk -v account="$ACCOUNT" ' match($0, /[^ ]/) && RSTART <= n {n = 0} n && NF == 1 && $1 == account ":" {getline; next} !n && /^ *admin::common::passwords:$/ { match($0, /[^ ]/) n = RSTART } {print}' < "$YAML"