如何通过Bash脚本从多个数组生成指定结构的JSON文件
Bash数组转指定结构JSON的解决方案
问题场景
你有以下关联的Bash数组(或字符串形式的数组):
# 作为JSON顶层键的数组(原字符串形式转成数组更可靠) arr1=(200 300 400) # 对应feature1的值 arr2=(1000 1001 1002) # 对应feature2的文件路径(来自你的工作流生成) arr3=("/path/to/1000.log" "/path/to/1001.log" "/path/to/1002.log")
需要生成嵌套结构的JSON,将arr1的元素作为顶层键,arr2、arr3的对应元素作为子对象的feature1、feature2值。之前直接传递整个数组给jq的方式会把数组当成单个字符串,无法生成预期的多键结构。
基础需求(仅两个数组)
方法1:Bash循环拼接JSON片段
适合逻辑简单、不想依赖复杂jq语法的场景:
arr1=(200 300 400) arr2=(1000 1001 1002) # 初始化JSON框架 json_output="{" # 遍历数组索引,逐个生成键值对 for idx in "${!arr1[@]}"; do key="${arr1[$idx]}" feature1_val="${arr2[$idx]}" # 非第一个元素前加逗号分隔 if [ "$idx" -gt 0 ]; then json_output="$json_output," fi json_output="$json_output\"$key\": {\"feature1\": $feature1_val}" done json_output="$json_output}" # 用jq格式化输出(可选,让JSON更美观) echo "$json_output" | jq .
方法2:jq数组配对(更简洁)
利用jq的数组处理功能,先将Bash数组转为jq可识别的JSON数组,再配对生成目标结构:
arr1=(200 300 400) arr2=(1000 1001 1002) jq -n --argjson keys "$(printf '%s\n' "${arr1[@]}" | jq -R . | jq -s .)" \ --argjson feature1_vals "$(printf '%s\n' "${arr2[@]}" | jq -nR . | jq -s .)" \ '[$keys, $feature1_vals] | transpose | map({(.[0]): {"feature1": .[1] | tonumber}}) | add'
printf '%s\n' "${arr1[@]}":将Bash数组元素逐行输出jq -R .:将每行内容转为JSON字符串jq -s .:将所有字符串转为JSON数组transpose:将两个数组按索引配对,生成[[key1, val1], [key2, val2], ...]的结构map:将每一组配对转为目标键值对象add:将所有对象合并为一个顶层JSON对象
补充需求(三个数组,含feature2)
基于你的工作流生成的arr1、arr2、arr3,用jq实现更高效:
# 先将原字符串形式的arr1转为Bash数组(你的工作流中arr1是字符串) arr1=($arr1) jq -n --argjson keys "$(printf '%s\n' "${arr1[@]}" | jq -R . | jq -s .)" \ --argjson feature1_vals "$(printf '%s\n' "${arr2[@]}" | jq -nR . | jq -s .)" \ --argjson feature2_vals "$(printf '%s\n' "${arr3[@]}" | jq -R . | jq -s .)" \ '[$keys, $feature1_vals, $feature2_vals] | transpose | map({(.[0]): {"feature1": .[1] | tonumber, "feature2": .[2]}}) | add'
tonumber:将feature1的字符串值转为数字类型(符合JSON格式要求)- 若
arr3的路径包含特殊字符(如空格),jq会自动处理转义,无需手动处理
如果偏好Bash循环方式,可参考基础需求的循环逻辑扩展:
arr1=($arr1) json_output="{" for idx in "${!arr1[@]}"; do key="${arr1[$idx]}" f1="${arr2[$idx]}" f2="${arr3[$idx]}" if [ "$idx" -gt 0 ]; then json_output="$json_output," fi json_output="$json_output\"$key\": {\"feature1\": $f1, \"feature2\": \"$f2\"}" done json_output="$json_output}" echo "$json_output" | jq .
为什么之前的方法失效
你之前用--arg arg1 "${arr1[*]}"传递数组时,${arr1[*]}会把数组元素拼接成一个空格分隔的字符串(如"200 300 400"),jq只会将其作为单个字符串处理,因此生成的是一个键为该字符串的单一条目,而非多个独立键值对。
内容的提问来源于stack exchange,提问作者gasar8
相关产品推荐
相关产品推荐

