如何用jq实现CSV转JSON通用化:按索引关联属性数组与CSV行
实现属性数组与CSV行的通用索引映射(jq+bash)
通用解决方案脚本
#!/bin/bash INPUT="$1" OUTPUT="$2" ATTRIB_NAMES=("name" "code" "email") MAIN_NAME="students" # 将bash数组转换为JSON数组,传递给jq ATTRIB_JSON=$(printf '%s\n' "${ATTRIB_NAMES[@]}" | jq -R . | jq -s .) jq --argjson attribs "$ATTRIB_JSON" --arg main_name "$MAIN_NAME" -Rsn ' {($main_name): [ inputs | split("\n")[] | select(length > 0) | split(";") as $input # 核心:通过索引遍历动态构建键值对 | reduce range(0; $attribs | length) as $i ({}; .[$attribs[$i]] = $input[$i]) ]} ' "$INPUT" > "$OUTPUT"
关键改动说明
正确传递属性数组
原脚本直接传递${ATTRIB_NAMES}会变成空格拼接的字符串,无法被jq识别为数组。这里通过printf+jq将bash数组转换为标准JSON数组,再用--argjson参数传入,确保jq能处理数组类型。动态构建映射对象
使用reduce遍历索引范围,逐个将$attribs[$i]作为键、$input[$i]作为值赋值给空对象,实现无需手动编写每个属性的通用映射。也可以用更简洁的等效写法替换reduce部分:[$attribs, $input] | transpose | map({key: .[0], value: .[1]}) | add原理是将属性数组和CSV字段数组转置,把每对元素转为键值对象后合并为一个完整对象。
增强通用性
用($main_name)作为动态键名,现在修改MAIN_NAME变量也能直接改变输出JSON的顶层键,无需修改jq代码。
测试示例
输入data.csv内容:
x;y;z a;b;c
运行脚本./your_script.sh data.csv final.json,输出final.json与原手动实现结果完全一致。若修改ATTRIB_NAMES=("id" "username" "phone"),则自动生成对应键名的JSON结构。
额外建议
- 若CSV字段包含分号(如带引号包裹的字段),建议先用专业工具(如
csvkit)预处理,或使用jq的CSV解析相关函数避免分割错误。 - 可添加参数校验逻辑,比如检查
$INPUT文件是否存在、$ATTRIB_NAMES是否非空,提升脚本健壮性。
内容的提问来源于stack exchange,提问作者eightShirt
相关产品推荐
相关产品推荐

