为了在INI文件的部分末尾添加一个键/值对,我想:
找到匹配部分名称并检查下一个方括号(即^ [)是否可用。如果是,则在这些行中找到最后一次出现的键/值对(即从匹配节名称到下一个方括号)。在最后一次出现的键/值对的末尾插入键/值对。
如果下一个方括号不可用,则将键/值对附加到文件的末尾。
对于情况(1),我可以使用sed检查下一个方括号是否可用,即
sed -i -e "/^\[$section\]/,/^\[.*\]/ ..."
但是,我不知道如何匹配key = value的最后一次出现。匹配最后一次出现的原因(而不是在下一个方括号之前添加ke / value对)是因为我可以选择在INI文件中的新键/值对之前引入换行符。例如,如果我想添加key10 = value10
[section1]
...
key8=value8
key9=value9
\n (could be multiple newline)
[section2]
变成
[section1]
...
key8=value8
key9=value9
\n (optional)
key10=value10
\n (could be multiple newline)
[section2]
请您能否建议我如何实现这一目标?
答案 0 :(得分:2)
为了完整起见(因为sed hackery是令人心旷神怡的乐趣),你可以用这样的sed来做:
/^\[section1\]/,/^\[/ {
x
/^$/ !{ x; H }
/^$/ { x; h }
d
}
x
/^\[section1\]/ {
s/\(\n\+[^\n]*\)$/\nkey10=value10\1/
p
x
p
x
d
}
x
p
将其放入文件中,例如foo.sed
,然后运行sed -n -f foo.sed foo.ini
。或者,如果您愿意,
sed '/^\[section1\]/,/^\[/ { x; /^$/ !{ x; H }; /^$/ { x; h; }; d; }; x; /^\[section1\]/ { s/\(\n\+[^\n]*\)$/\nkey10=value10\1/; p; x; p; x; d }; x' foo.ini
......似乎已经不够难读了。
使用保持缓冲区很有趣;第一位匹配从[section1]
到下一节开头的所有行,然后将所有行放入保持缓冲区(并在那里突破)。如果我们不在那个部分,其余的交换保持缓冲区,检查section1是否在其中,如果是,在适当的位置将key10=value10
替换为它,打印它,交换模式空间,打印它,将保留空间重新交换并删除它(现在第1节之后的行在保持缓冲区中,但我们不再关心它了)。剩下的时间,模式空间只是换回并打印出来,所以从那里开始就像cat
一样。
编辑:NeronLeVelu指出,只有在[section1]
之后有一个模式范围可以匹配的部分时,这才有效。如果不能保证,那么在第1部分尚未处理的情况下需要对最后一行进行特殊处理。这可以做到:
$ {
H
x
/^\[section1\]/ {
s/\n\+$//
a key10=value10
x
}
x
p
d
}
/^\[section1\]/,/^\[/ {
x
/^$/ !{ x; H }
/^$/ { x; h }
d
}
x
/^\[section1\]/ {
s/\(\n\+[^\n]*\)$/\nkey10=value10\1/
p
x
p
x
d
}
x
p
这将处理最后一行与其他行不同;它会将它附加到保持缓冲区,检查section1是否还需要处理,如果是,则追加key10=value10
并交换回来,然后再次交换并打印出模式空间。这个令人困惑的分流位意味着如果section1仍在保持缓冲区中,则打印保持缓冲区,否则打印最后一行。
到目前为止,我不得不指出,一旦sed脚本变得这么长,就值得考虑其他选择。
答案 1 :(得分:1)
你可以使用这个awk:
awk -v sec='[section1]' -v kv='key10=value10' 'p && $1~/\[[^]]*\]/{p=0; print kv}
$1==sec{p=1} END{if (p) print kv} 1' file
[section1]
...
key8=value8
key9=value9
key10=value10
[section2]
答案 2 :(得分:0)
另一种hacky awk方式
awk -v k='key10=value10' '($1=="[section1]"||x&&/^\[/)&&!(x=!x){print k}
END{if(x)print k}1' file
检查字段1是否等于[section1]
或x是否不是0
如果其中任何一个为真,则将x设置为x的倒数并检查它是否为0
如果为0则打印键值对。
最后如果x仍然设置,则打印键值对
1打印所有行
答案 3 :(得分:0)
sed -i '/^\[section1]/,/^\[/ {
$ a\
key10=value10
/^\[section1]/ !{
/[^=#]\{1,\}=/ !i\
key10=value10
}
}' YourFile
--posix
[section1]
名称的出现次数以选择所需部分key10=value10
答案 4 :(得分:0)
我建议使用专门用来操作ini文件的dedicated program而不是用sed发明一个几乎圆而脆弱的轮子,而不是简单易用:
$ cat test.conf | tee test.conf.orig
[section1]
##...
key8=value8
key9=value9
[section2]
abc=123
$ crudini --set test.conf section1 key10 value10
$ diff -u test.conf.orig test.conf
--- test.conf.orig 2017-10-10 20:59:55.205678995 +0200
+++ test.conf 2017-10-10 21:00:00.831477388 +0200
@@ -2,6 +2,7 @@
##...
key8=value8
key9=value9
+key10 = value10
$