如何将bash脚本中的json解析为数组?数组值应该同时具有 key:value 格式
Posted
技术标签:
【中文标题】如何将bash脚本中的json解析为数组?数组值应该同时具有 key:value 格式【英文标题】:how to parse json in bash script as an array? array value should have both key:value format 【发布时间】:2021-09-29 19:29:02 【问题描述】:我的 json.file 看起来像
"price1" : "120.10",
"price2" : "110.30",
"price3" : "244.45"
我在我的 bash 脚本中使用了下面的 sed 命令来声明从 json 读取的数组
array=( $(sed -n '//,//s/[^:]*:[^"]*"\([^"]*\).*/\1/p;' json.file) )
这给了我echo $array[*]
值的输出
120.10 110.10 244.45
我正在寻找包含键名的数组值 (key:value
)。
我想要的输出应该是key:value
格式
price1:120.10 price2:110.10 price3:244.45
有人可以帮助或指导我吗?
【问题讨论】:
您的输入不是有效的 JSON,您的意思是"price1":"120.10","price2":"110.30","price3":"244.45"
啊是的。我的错你是对的。这就是我的正确格式
【参考方案1】:
用sed
解析json
可能是个坏主意。但是让我们假设它是一种超级简单且常规的json
格式。您离可行的解决方案不远了:
$ array=($(sed -nr 's/.*"(.*)".*"(.*)".*/\1:\2/p' json.file))
$ echo $array[*]
price1:120.10 price2:110.30 price3:244.45
substitute 命令的 p
标志告诉 sed 如果有匹配则打印结果。很高兴知道。如果每条感兴趣的行只有两个带引号的字符串,它应该可以工作。正则表达式 .*"(.*)".*"(.*)".*
匹配任何内容 - .*
- 后跟一个双引号,再次是任何内容,另一个双引号......括号 - (.*)
- 不要更改匹配的内容。它只是在可用于替换字符串的九个缓冲区之一中记录括号之间的匹配部分 - \1:\2
。所以这里,替换字符串对应:
<first recorded match>:<second recorded match>
如果您想更具体地了解匹配行,您可以。例如:
sed -nr 's/^ "(.*)" : "(.*)",?$/\1:\2/p' json.file
还指定有 2 个前导空格,冒号前后各有一个空格,最后一个引号之后和行尾之前有一个可选的逗号。
但也有更简单的:
sed -nr 's/[[:space:]",]//gp' json.file
只删除所有空格、双引号和逗号,只打印匹配的行。你猜怎么着?这是你(显然)想要的。
无论如何,请记住,如果您的 json
文件比您显示的更复杂,sed
绝对不是正确的工具。
【讨论】:
当其他用户搜索 SO 时,最好有明确分开的问题。因此,请提出一个单独的问题,并明确说明您想要什么,并发送Minimal, Reproducible Example。 只是想了解 sed 命令的哪一部分只获取密钥?假设我的输出只是来自 json 的键而不是值 @gmpy1990 我不明白。您是删除了之前的评论还是我评论了错误的问题? 我已经删除了我之前的问题,因为你提到它是一个单独的(不相关的问题) @gmpy1990 哦,我明白了。好的,让我在我的答案中添加一些关于 sed 正则表达式的解释。【参考方案2】:对于 bash 脚本,您可能希望使用关联数组:
declare -A prices
while IFS=$'\t' read -r key value; do
prices[$key]=$value
done < <(
jq -r 'to_entries[] | [.key, .value] | @tsv' json.file
)
然后,检查数组
declare -p prices
declare -A prices='([price1]="120.10" [price3]="244.45" [price2]="110.30" )'
或对其进行迭代
for key in "$!prices[@]"; do
printf '%s => %s\n' "$key" "$prices[$key]"
done
price1 => 120.10
price3 => 244.45
price2 => 110.30
【讨论】:
【参考方案3】:json='"price1":"120.10","price2":"110.30","price3":"244.45"'
array=($(jq -r 'to_entries[] | ( "\(.key):\(.value)")' <<< "$json"))
echo $array[@]
printf '%s\n' "$array[@]"
declare -p array
echo
array=($(jq -r 'to_entries[] | ( "\(.key):\(.value)") | @sh' <<< "$json"))
echo $array[@]
printf '%s\n' "$array[@]"
declare -p array
输出:
price1:120.10 price2:110.30 price3:244.45
price1:120.10
price2:110.30
price3:244.45
declare -a array='([0]="price1:120.10" [1]="price2:110.30" [2]="price3:244.45")'
'price1:120.10' 'price2:110.30' 'price3:244.45'
'price1:120.10'
'price2:110.30'
'price3:244.45'
declare -a array='([0]="'\''price1:120.10'\''" [1]="'\''price2:110.30'\''" [2]="'\''price3:244.45'\''")'
【讨论】:
【参考方案4】:您的解决方案只需要提取额外的数据:
array=( $(sed -n '//,//s/"\([^"]*\)"[^:]*:[^"]*"\([^"]*\).*/\1:\2/p;' <<< "$j") )
echo $array[@]
price1:120.10 price2:110.30 price3:244.45
看起来更简单的解决方案也可能有效,但我假设您是故意这样编写模式的。
这里的关键技巧是用转义括号 \(...\)
将模式的一部分括起来,然后在输出部分 \1
、\2
等中对每个进行编号替换。
【讨论】:
以上是关于如何将bash脚本中的json解析为数组?数组值应该同时具有 key:value 格式的主要内容,如果未能解决你的问题,请参考以下文章
如何使用 Newtonsoft.Json 将包含数组数组的 json 对象解析为 C# 中的对象列表?
如何将 JSON 数组中的值解析为 BigQuery 中的列