📅  最后修改于: 2023-12-03 15:02:26.011000             🧑  作者: Mango
在日常的开发工作中,我们时常需要将数据进行转换成不同格式,其中 Json 和 Csv 的转换是比较常见的一种。此篇介绍如何利用 Shell-Bash 来进行 Json 到 Csv 的转换。
在 Shell-Bash 中,可以利用 jq
工具来解析 Json 数据。安装方式如下:
# Debian / Ubuntu
$ sudo apt-get install jq
# RedHat / CentOS
$ sudo yum install jq
# macOS
$ brew install jq
例如我们有一个 Json 文件 data.json
,内容如下:
{
"students": [
{
"name": "Tom",
"age": 18,
"gender": "male",
"scores": [88, 90, 92]
},
{
"name": "Jerry",
"age": 19,
"gender": "female",
"scores": [90, 92, 94]
}
]
}
可以使用以下命令读取其中的数据:
# 读取所有数据
$ cat data.json | jq '.'
# 读取某个字段的数据
$ cat data.json | jq '.students[0].name'
# 读取数组的数据
$ cat data.json | jq '.students[0].scores[]'
通过 jq
解析后,得到的是 Json 格式的数据,需要进一步转换成 Csv 格式。以下是一个比较通用的转换方法:
# 定义变量
delimiter="," # Csv 文件的分隔符
array_start=0 # 数组起始下标
array_end=-1 # 数组结束下标,默认-1表示全部
keys=() # 列名集合,动态生成
# 解析Json数据
cat data.json | jq -r '.students[] | @csv'
# 读取列名
cat data.json | jq -r '.students[0] | keys[]' | while read key
do
if [ "$key" = "scores" ]
then
count=($(cat data.json | jq ".students[$array_start:$array_end] | .$key[] | length" | sort -u))
for (( i=0; i<$count; i++ ))
do
keys+=("\"$key[$i]\"")
done
else
keys+=("\"$key\"")
fi
done
# 生成 Csv 数据
cat data.json | jq -r --arg delimiter "$delimiter" --argjson keys "${keys[*]}" \
-r '.students[0] | to_entries | sort_by(.key) | .[].value | @csv' | tr -d '\r' |
sed "1s/.*/${keys[@]}/" | sed "2,$ s|$|${delimiter//\\/}|g"
以上脚本中,通过 jq
工具解析出列名集合,在第一行输出,然后输出数据行,通过 sed
工具将换行符替换成 Csv 文件的分隔符。
以上方法仅限于 Json 中不包含嵌套的数组。如果有嵌套的数组,可以参考flatten
函数的实现方法。附上代码供参考:
flatten() {
if [[ $(echo "$1" | jq -r 'type') == 'array' ]]; then
jq -r '
map(
if type == "object" then
to_entries | flatten
elif type == "array" then
flatten
else
.
end
) | add
'
else
echo "$1"
fi
}
# 使用方式如下:
flatten "$1" | jq -r 'map(tostring | gsub("\""; "\"\"")) | @csv'
以上介绍了如何通过 Shell-Bash 实现 Json 到 Csv 的转换。其中需要注意的点是:
jq
工具解析 Json 数据在实际应用中,需要根据实际的数据结构进行适当的调整。此篇介绍的方法仅供参考。