Hyd*_*Ura 14 unix csv bash json jq
尝试将CSV文件转换为JSON
这是两个示例行:
-21.3214077;55.4851413;Ruizia cordata
-21.3213078;55.4849803;Cossinia pinnata
Run Code Online (Sandbox Code Playgroud)
我想得到类似的东西:
"occurrences": [
{
"position": [-21.3214077, 55.4851413],
"taxo": {
"espece": "Ruizia cordata"
},
...
}]
Run Code Online (Sandbox Code Playgroud)
这是我的脚本:
echo '"occurences": [ '
cat se.csv | while read -r line
do
IFS=';' read -r -a array <<< $line;
echo -n -e '{ "position": [' ${array[0]}
echo -n -e ',' ${array[1]} ']'
echo -e ', "taxo": {"espece":"' ${array[2]} '"'
done
echo "]";
Run Code Online (Sandbox Code Playgroud)
我得到了非常奇怪的结果:
"occurences": [
""position": [ -21.3214077, 55.4851413 ], "taxo": {"espece":" Ruizia cordata
""position": [ -21.3213078, 55.4849803 ], "taxo": {"espece":" Cossinia pinnata
Run Code Online (Sandbox Code Playgroud)
我的代码出了什么问题?
jst*_*aab 14
这是一个可以解决问题的python单行/脚本:
cat my.csv | python -c 'import csv, json, sys; print(json.dumps([dict(r) for r in csv.DictReader(sys.stdin)]))
Run Code Online (Sandbox Code Playgroud)
Cha*_*ffy 13
这项工作的正确工具是jq
.
jq -Rsn '
{"occurrences":
[inputs
| . / "\n"
| (.[] | select(length > 0) | . / ";") as $input
| {"position": [$input[0], $input[1]], "taxo": {"espece": $input[2]}}]}
' <se.csv
Run Code Online (Sandbox Code Playgroud)
在您输入的情况下发出:
{
"occurences": [
{
"position": [
"-21.3214077",
"55.4851413"
],
"taxo": {
"espece": "Ruizia cordata"
}
},
{
"position": [
"-21.3213078",
"55.4849803"
],
"taxo": {
"espece": "Cossinia pinnata"
}
}
]
}
Run Code Online (Sandbox Code Playgroud)
顺便说一句,原始脚本的错误版本可能如下:
#!/usr/bin/env bash
items=( )
while IFS=';' read -r lat long pos _; do
printf -v item '{ "position": [%s, %s], "taxo": {"espece": "%s"}}' "$lat" "$long" "$pos"
items+=( "$item" )
done <se.csv
IFS=','
printf '{"occurrences": [%s]}\n' "${items[*]}"
Run Code Online (Sandbox Code Playgroud)
注意:
cat
管道进入循环是绝对没有意义的(并且有很好的理由); 因此,我们使用重定向(<
)直接打开文件作为循环的标准输入.read
可以传递目标变量列表; 因此,不需要读入数组(或者首先读取一个字符串,然后生成一个heresting并从中读取到一个数组中).所述_
在端部保证了额外的列将被抛弃(通过将它们到名为虚变量_
),而不是附加到pos
."${array[*]}"
通过连接array
字符的元素生成一个字符串IFS
; 因此,我们可以使用它来确保只在需要时输出中存在逗号.printf
echo
如在本说明书echo
的"应用程序使用"部分中所建议的那样,优先使用它.ric*_*ler 13
John Kerl 的Miller工具内置了以下功能:
mlr --c2j --jlistwrap cat INPUT.csv > OUTPUT.json
Run Code Online (Sandbox Code Playgroud)
Ram*_*man 11
接受的答案用于jq
解析输入。这有效但jq
不处理转义,即从 Excel 或类似工具生成的 CSV 输入的引用如下:
foo,"bar,baz",gaz
Run Code Online (Sandbox Code Playgroud)
将导致错误的输出,因为 jq 将看到 4 个字段,而不是 3 个。
一种选择是使用制表符分隔值而不是逗号(只要您的输入数据不包含制表符!),以及接受的答案。
另一种选择是组合您的工具,并为每个部分使用最好的工具:CSV 解析器,用于读取输入并将其转换为 JSON,并将jq
JSON 转换为目标格式。
基于 python 的csvkit将智能地解析 CSV,并附带一个工具csvjson
,可以更好地将 CSV 转换为 JSON。然后可以通过 jq 将其通过管道传输,以将 csvkit 的平面 JSON 输出转换为目标形式。
使用 OP 提供的数据,对于所需的输出,这很简单:
csvjson --no-header-row |
jq '.[] | {occurrences: [{ position: [.a, .b], taxo: {espece: .c}}]}'
Run Code Online (Sandbox Code Playgroud)
需要注意的是csvjson自动检测;
作为分隔符,并且没有标题行中的输入,分配JSON键作为a
,b
,和c
。
这同样也适用于写到CSV文件-csvkit
可以读取一个JSON数组或新线过分隔的JSON,并智能输出CSV in2csv
。
这是一篇关于这个主题的文章:https : //infiniteundo.com/post/99336704013/convert-csv-to-json-with-jq
它还使用 JQ,但使用split()
和 的方法略有不同map()
。
jq --slurp --raw-input \
'split("\n") | .[1:] | map(split(";")) |
map({
"position": [.[0], .[1]],
"taxo": {
"espece": .[2]
}
})' \
input.csv > output.json
Run Code Online (Sandbox Code Playgroud)
但是,它不处理分隔符转义。
这是 Ruby 的单行解决方案:
ruby -r json -r csv -e 'puts CSV.parse(STDIN, headers:true).map(&:to_h).to_json' < INPUT.csv
Run Code Online (Sandbox Code Playgroud)