将AWS命令JSON输出转为Bash环境变量:当前方法是否高效通用?
AWS JSON解析脚本的问题反馈与适配性疑问
我写了一段脚本用来解析AWS命令的JSON输出并提取值,脚本能正常运行,但我觉得它肯定有问题。我能找到的资料都是处理已知"key":"value"键值对的,而我的脚本好像能处理任意键值对,想听听大家的反馈。另外我还想知道,这个脚本能不能适配AWS所有场景的JSON输出,还是实际用的时候得不停调试?
rm -f tmp.file cmd="aws sns list-subscriptions-by-topic --topic-arn arn:aws:sns:eu-west-1:${account}:${topic}" #this is the command that produces JSON eval "${cmd}" | jq . | tr -d "{" | tr -d "}" | tr -d "," | tr -d "[" | tr -d "]" | tr -d " " | grep -v '^[[:space:]]*$' | while read LINE; do # The above line strips JSON-specific chars and feeds what is left line by line into a loop varname=$(echo "${LINE}" | cut -d ":" -f1 | tr -d '"') #key is whatever comes before ":" value=$(echo "${LINE}" | cut -d ":" -f2-) #value is whatever comes after ":" if [ "${value}" != "" ]; then echo "${varname}+=(${value})" >> tmp.file #we create a temp file that adds values to an array named by key elements fi done #here we source the tmp.file and remove it source tmp.file & rm -f tmp.file
脚本存在的核心问题
- 完全依赖JSON的扁平格式化结构:你用
jq .把JSON换行格式化,但只要遇到嵌套对象(比如{"a": {"b": "c"}}),tr去掉括号后会把a:{"b":"c"和b:"c"拆成两行,这时候cut拆分出来的键值对完全丢失了层级关系,逻辑直接出错。 - 键值拆分逻辑脆弱:用
:作为分隔符,但如果值本身包含冒号(比如ARN、时间戳2024-05-20T12:34:56Z、带冒号的字符串),虽然cut -f2-能保留后续内容,但如果是嵌套结构里的冒号,会直接把嵌套键当成独立键处理,完全乱套。 - 数组处理彻底失效:比如AWS输出的数组
["item1", "item2"],处理后会变成无对应键的"item1"、"item2"行,要么被忽略,要么会导致source时语法错误;如果是{"items": ["a", "b"]},处理后items数组是空的,后续的"a"、"b"没有键,完全丢失上下文。 - 引号与特殊字符处理不当:值里的双引号没清理干净,比如
"SubscriptionArn":"arn:aws:sns:..."处理后value是"arn:aws:sns:...",如果值里包含空格、引号或者bash特殊字符(比如$、!),直接放进数组会触发bash语法错误。 - 临时文件竞态问题:
source tmp.file & rm -f tmp.file用后台执行source然后立刻删文件,大概率会出现source还没读完文件就被删除的情况,导致变量导入失败。应该先执行source再删除文件,不需要&。
适配性结论
这个脚本绝对无法适配AWS所有场景的JSON输出。AWS不同命令的JSON输出结构差异极大:有的是多层嵌套对象,有的是包含复杂元素的数组,还有数字、布尔值、null等非字符串类型。你的脚本只适用于完全扁平、无嵌套、值不含特殊字符的极简JSON结构,比如你测试的sns list-subscriptions-by-topic输出可能刚好符合,但换个命令(比如aws ec2 describe-instances、aws s3api list-objects),处理后会丢失大量结构信息,甚至直接报错。实际使用中肯定需要反复调试,而且根本覆盖不了大部分场景。
改进建议
既然已经用到了jq,不如直接用它完成所有JSON解析和bash变量生成的工作,逻辑更可靠,也能处理绝大多数AWS JSON输出场景。比如针对你当前的需求,可以改成这样:
# 直接用jq生成合法的bash数组定义,避免手动处理JSON字符 aws sns list-subscriptions-by-topic --topic-arn arn:aws:sns:eu-west-1:${account}:${topic} | jq -r ' .Subscriptions[] | to_entries[] | # 把值转成字符串,并用双引号包裹,避免特殊字符问题 "\(.key)+=(\"\(.value | tostring)\")" ' > tmp.file # 先source再删文件,避免竞态问题 source tmp.file rm -f tmp.file
这个版本能正确处理嵌套值、特殊字符,也能保留键值对的对应关系,比你原来的脚本稳定得多。
内容的提问来源于stack exchange,提问作者sheikhness
相关产品推荐
相关产品推荐

