如何让Bash的declare命令支持含空格的变量值?
解决
declare处理awk生成的带空格变量值问题 这是《awk gsub未替换字段中所有句点》的续篇,先还原场景:
场景重现
配置文件ipv4settings.txt内容:
$ cat ./ipv4settings.txt ipv4.gateway: 192.168.2.1 ipv4.routes: -- ipv4.route-metric: -1 ipv4.route-table: 0 (unspec)
用awk生成变量定义格式的输出:
$ awk 'BEGIN{FS=":[[:space:]]+";OFS="="}{gsub("[.]|-","_",$1);$1=$1;print $1"="$2 }' ./ipv4settings.txt ipv4_gateway=192.168.2.1 ipv4_routes=-- ipv4_route_metric=-1 ipv4_route_table=0 (unspec)
执行declare导入这些变量时触发报错:
-bash: declare: `(unspec)': not a valid identifier
问题根源:bash解析时会把空格后的(unspec)当成独立参数,而变量名不允许包含括号、空格这类字符,导致识别失败。
可行解决方案
方案1:awk输出带单引号包裹值的声明,直接source导入
修改awk命令,将变量值用单引号包裹,同时转义值内可能存在的单引号,确保bash能正确识别完整值:
awk 'BEGIN{FS=":[[:space:]]+"} { gsub("[.]|-","_",$1) # 提取完整的变量值(包含所有后续内容) val=$0 sub(/^[^:]+:[[:space:]]+/,"",val) # 转义值中的单引号,避免语法错误 gsub(/'\''/,"'\''\\'\'''\''",val) # 输出完整的declare命令 print "declare -x " $1 "='\''" val "'\''" }' ./ipv4settings.txt | source /dev/stdin
执行后变量直接导入当前shell环境,可直接使用echo $ipv4_route_table验证。
方案2:用read逐行解析变量名和值
通过read拆分键值对,再调用declare,避免直接传递整行的语法问题:
# 先开启扩展glob,用于匹配开头的所有空格 shopt -s extglob while IFS=":" read -r key rest; do # 替换键中的.和-为_ key=${key//[.-]/_} # 去掉值开头的所有空格 value=${rest##+([[:space:]])} declare "$key=$value" done < ./ipv4settings.txt
方案3:awk输出带双引号包裹值的定义
如果值不含双引号,也可以用双引号包裹,注意转义值内的双引号(如果存在):
awk 'BEGIN{FS=":[[:space:]]+"} { gsub("[.]|-","_",$1) val=$0 sub(/^[^:]+:[[:space:]]+/,"",val) # 转义值中的双引号 gsub(/"/,"\\\"",val) print $1 "=\"" val "\"" }' ./ipv4settings.txt | while read -r line; do declare "$line"; done
内容的提问来源于stack exchange,提问作者aenagy
相关产品推荐
相关产品推荐

