有没有办法读取由制表符分隔的键值对?

时间:2019-06-17 12:37:44

标签: shell awk sed configuration grep

我正在基于配置文件编写建筑环境,但无法解析它们。该环境包含Makefile(bmake),这些文件会尝试读取相应的设置CFLAGS的配置。

配置文件保持简单,不需要特殊的=签名:

ident               Appname           # E.g. core.S:15: .ident $ident$
cpu                 arch (amd64, x86) # -march=cpuarch -mtune=cpuarch

option              debug             # Enable debugging.
option              sanitize          # Sanitize undefined behaviour.
option              asyncio           # Asynchronous I/O.
option              ccpipe            # GCC/Clang -pipe option.

我无法找出使用grepsedawk解析这些选项的正确正则表达式。因为我希望通过conditional statements通过简单的bmake(例如

)来确定这些功能
DBG_ENABLED!= $read if option debug is set$ ? yes : no.
.if ${DBG_ENABLED} != ""} || ${DBG_ENABLED} == "yes" || ${DBG_ENABLED} != "no"
CFLAGS+=      -O -g
.else
CFLAGS+=      -O2
.endif

PIPE_ENABLED!= $read if option ccpipe is set$ ? yes : no.
.if ${PIPE_ENABLED} != "no"
CFLAGS+=      -pipe
.endif

因此,如何通过外壳命令确定选项X,例如option debug,设置好了吗?我想到过要grepping文件或使用awk ...

1 个答案:

答案 0 :(得分:3)

将配置文件读入关联数组:

$ declare -A opts="( $(awk -F'\t+' 'NF{print "["$1","$2"]=1"}' file) )"

$ for idx in "${!opts[@]}"; do echo "$idx=${opts[$idx]}"; done
cpu,arch (amd64, x86)=1
option,debug=1
option,asyncio=1
option,ccpipe=1
option,sanitize=1
ident,Appname=1

然后只需测试${opts["option,debug"]}是否已填充。

或者,如果您只想获得这些选项:

$ declare -A opts="( $(awk -F'\t+' '$1=="option"{print "["$2"]=1"}' file) )"

$ for idx in "${!opts[@]}"; do echo "$idx=${opts[$idx]}"; done
ccpipe=1
sanitize=1
asyncio=1
debug=1

您喜欢的语法:

$ if (( ${opts[debug]} )); then echo "do debug stuff"; else echo "nope, dont do it"; fi
do debug stuff

$ if (( ${opts[fluff]} )); then echo "do debug stuff"; else echo "nope, dont do it"; fi
nope, dont do it

$ if [[ -n ${opts[debug]} ]]; then echo "do debug stuff"; else echo "nope, dont do it"; fi
do debug stuff

$ if [[ -n ${opts[fluff]} ]]; then echo "do debug stuff"; else echo "nope, dont do it"; fi
nope, dont do it

更新:由于您的文件显然不是按照您所说的那样用制表符分隔的,因此请删除注释,然后删除所有剩余的前导/后缀空格,并使用剩余的前一个空格链作为第一个字段与该行的其余部分(必须在第一个脚本中将arch (amd64, x86)视为“字段”)

$ declare -A opts="( $(awk '{sub(/#.*/,""); gsub(/^[[:space:]]+|[[:space:]]+$/,"")} NF{k=$1; sub(/[^[:space:]]+[[:space:]]+/,""); print "["k","$0"]=1"}' file) )"

$ for idx in "${!opts[@]}"; do echo "$idx=${opts[$idx]}"; done
cpu,arch (amd64, x86)=1
option,debug=1
option,asyncio=1
option,ccpipe=1
option,sanitize=1
ident,Appname=1

$ declare -A opts="( $(awk '{sub(/#.*/,""); gsub(/^[[:space:]]+|[[:space:]]+$/,"")} $1=="option"{print "["$2"]=1"}' file) )"

$ for idx in "${!opts[@]}"; do echo "$idx=${opts[$idx]}"; done
ccpipe=1
sanitize=1
asyncio=1
debug=1

最终更新:所有考虑到的事情可能就是您真正想要的:

$ declare -A opts="( $(awk '
{
    sub(/#.*/,"")
    gsub(/^[[:space:]]+|[[:space:]]+$/,"")
}

NF && ($1 != "ident") {
    f1 = $1
    sub(/[^[:space:]]+[[:space:]]+/,"")
    f2 = $0
    if (f1 == "option") {
        idx = f2
        val = 1
    } else {
        idx = f1
        val = f2
    }
    print "[" idx "]=\"" val "\""
}
' file ) )"

$ for idx in "${!opts[@]}"; do echo "$idx=${opts[$idx]}"; done
ccpipe=1
sanitize=1
asyncio=1
debug=1
cpu=arch (amd64, x86)