bash - 在bash中,将CSV转换为JSON

试图将CSV文件转换为JSON

下面是两个例子:


-21.3214077;55.4851413;Ruizia cordata


-21.3213078;55.4849803;Cossinia pinnata



我想得到一些类似的东西:


"occurrences": [


 {


"position": [-21.3214077, 55.4851413],


"taxo": {


"espece":"Ruizia cordata"


 },


 ...


 }]



这是我的脚本:


 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"]";



我得到了很奇怪的结果


"occurences": [ 


""position": [ -21.3214077, 55.4851413 ],"taxo": {"espece":" Ruizia cordata


""position": [ -21.3213078, 55.4849803 ],"taxo": {"espece":" Cossinia pinnata



我的代码有什么问题?

时间:

实现这个工作的正确工具是jq 。


jq -Rsn '


 {"occurrences":


 [inputs


 | . /"n"


 | (.[] | select(length > 0) | . /";") as $input


 | {"position": [$input[0], $input[1]],"taxo": {"espece": $input[2]}}]}


' <se.csv



根据输入给出:


{


"occurences": [


 {


"position": [


"-21.3214077",


"55.4851413"


 ],


"taxo": {


"espece":"Ruizia cordata"


 }


 },


 {


"position": [


"-21.3213078",


"55.4849803"


 ],


"taxo": {


"espece":"Cossinia pinnata"


 }


 }


 ]


}



顺便说一下,你原始脚本的一个较短的版本如下所示:


#!/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[*]}"



注:

  • 使用cat来进入循环(还有不是好的方法 )是没有意义的; 因此,我们使用重定向(< )直接作为循环的stdin打开文件,
  • read可以传递一个目标变量列表; 因此,不需要读入数组(或者首先读入一个字符串,然后生成一个heresting,并且从中读取到一个数组中)。最终的_确保额外的列被丢弃(通过将它们放入名为_的虚拟变量中)而不是追加到pos
  • "${array[*]}"通过将array的元素与IFS中的字符连接起来生成字符串; 因此,我们可以使用它来确保只有在需要时才在输出中显示逗号。
  • printf优先于echo ,echo的规范 ,
  • 这仍然是错误的,因为它通过字符串连接生成JSON。不要用它。

有关主题的文章: 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



通常,如果jq有inputs filter (jq 1.5以上版本可用),那么最好使用它,而不是使用-s命令行选项。

在任何情况下都使用inputs的解决方案,这个解决方案也是无变量的。


{"occurrences":


 [inputs


 | select(length > 0)


 | . /";"


 | {"position": [.[0], .[1]], 


"taxo": {"espece": .[2]}} ]}



SSV,CSV等等

当然,上面假设该文件在每一行中都有以分号分隔的字段,并且没有与CSV文件相关的复杂情况。

如果你喜欢JS,可以使用smk ()来完成,https://www.npmjs.com/package/smk ),


npm install -g smk



cat t1.txt | smk -a -f"(a) => JSON.stringify({


 'occurrences': a.map((row) => row.split(';')).map((arr) => ({


 'position': [parseFloat(arr[0]), parseFloat(arr[1])],


 'taxo': {


 'espece': arr[2]


 }


 }))


 }, null, 4)";




xidel -s input.csv --xquery '


 {


"occurrences":for $x in tokenize($raw,"n") let $a:=tokenize($x,";") return {


"position":[


 $a[1],


 $a[2]


 ],


"taxo":{


"espece":$a[3]


 }


 }


 }


'




{


"occurrences": [


 {


"position": ["-21.3214077","55.4851413"],


"taxo": {


"espece":"Ruizia cordata"


 }


 },


 {


"position": ["-21.3213078","55.4849803"],


"taxo": {


"espece":"Cossinia pinnata"


 }


 }


 ]


}



...