使用sed/awk从ini样式文件中读取值

smi*_*ael 4 bash awk ini sed

我写了一个简单的bash函数,它将从ini文件(由变量定义CONF_FILE)中读取值并输出它

getConfValue() {
 #getConfValue section variable
 #return value of a specific variable from given section of a conf file
 section=$1
 var="$2"
 val=$(sed -nr "/\[$section\]/,/\[/{/$var/p}" $CONF_FILE)
 val=${val#$var=}
 echo "$val"
}
Run Code Online (Sandbox Code Playgroud)

问题是,如果节名称中的多个变量共享公共子串,它不会忽略注释并遇到麻烦.

示例ini文件:

[general]
# TEST=old
; TEST=comment  
TEST=new
TESTING=this will be output too
PATH=/tmp/test
Run Code Online (Sandbox Code Playgroud)

运行getConfValue general PATH将按/tmp/test预期输出,但运行getConfValue general TEST显示此方法存在的所有问题.

如何解决?

我知道有一些专用的工具,比如crudinipython,perl和php的工具,但是我不希望为简单的配置文件解析添加额外的依赖.结合awk而不是sed的解决方案也可以.

JNe*_*ill 6

坚持使用sed可以将var搜索锚定到记录的开头,^并以等号结束:

"/\[$section\]/,/\[/{/^$var=/p}"
Run Code Online (Sandbox Code Playgroud)

如果您担心记录前面的空格,您可以考虑到:

"/\[$section\]/,/\[/{/^(\W|)$var=/p}"
Run Code Online (Sandbox Code Playgroud)

^(\W|)$var=表示"如果在变量与等号()连接之前,开头有空格(^(\W)或者没有|)($var=)."

如果你想切换到awk,你可以使用类似的东西:

val=$(awk -F"=" -v section=$section -v var=$var '$1=="["section"]"{secFound=1}secFound==1 && $1==var{print $2; secFound=0}' $CONF_FILE)
Run Code Online (Sandbox Code Playgroud)

awk命令将记录拆分相等-F"=".然后,如果记录中的第一个字段是你的section($1=="["section"]")然后将变量设置secFound为1.然后...如果secFound是1并且第一个字段完全等于你的var变量(secFound==1 && $1==var)然后打印出第二个字段({print $2})并设置secFound为0所以我们不会拿起任何其他Test钥匙.