我有两个文件:修改.csv和sample.json。我的csv文件如下:
header "a", "b"
"a11","b1"
"a22","b2"
"a33","b3"
json文件是这样的:
[
{"a":"a1","b":"b1"},
{"a":"a2","b":"b2"},
{"a":"a3","b":"b3"},
{"a":"a4","b":"b4"}
]
我需要编写一个jq命令,该命令使用csv文件在json文件中进行更改,即json文件的最终输出应如下所示:
[
{"a":"a11","b":"b1"},
{"a":"a22","b":"b2"},
{"a":"a33","b":"b3"},
{"a":"a4","b":"b4"}
]
我编写了以下命令:
while IFS=",", read f1 f2
do
jq --argjson k1 $f1 --argjson k2 $f2 '(.[] | select(.b == $k2) | .a) |= $k1' sample.json| sponge sample.json
done < changes.csv
虽然每次迭代它都能过滤和更新key“a”的值,但是当我尝试将结果海绵到json文件中时,它却无法做到这一点,不知道我到底错过了什么。
3条答案
按热度按时间j2datikz1#
假设CSV行为良好,您可以编写:
对于更复杂的CSV,您可能希望使用CSV到JSON或CSV到TSV工具(这两种工具都可以很容易地用jq编写--参见https://rosettacode.org/wiki/Convert_CSV_records_to_TSV#jq)
如果您不喜欢使用--argfile选项,那么可以使用其他方法阅读这两个文件,例如,您可以使用--rawfile读取CSV,而保留STDIN读取JSON。
2fjabf4q2#
对于纯粹的
jq
解决方案,最好确保CSV在任何字段中都不包含任何,
或"
或\n
,否则代码将变得复杂得多。因此,我建议使用Miller(可用于多个操作系统的here)解决方案,它可以轻松、可靠地完成任务:
让我们分解命令:
将在字段
b
上连接 * file1 * 和 * file2 。当b
以外的字段存在于两个文件中时(例如a
),则输出的是 * file2 * 的值。因此,要使用CSV中的值更新JSON, file1 * 应为JSON,* file2 * 应为CSV。
--ul
表示输出 * file1 * 不可连接的行;没有它,输出将仅包含已经"配对"的记录。join
动词,Miller允许为 * file1 * 指定与 * file2 * 不同的输入格式;您将默认输入格式设置为--icsv
(用于处理 * file2 *),并在join
动词(用于处理 * file1 *)之后用--ijson
覆盖它。--ojson
表示每行输出一条"记录"。5t7ly7z53#
所以我发现如果我把csv文件的值转换成输入可读的格式,并使用--arg代替--argjson,文件就能很好地更新。所以,命令
awk '{gsub(/"/,"")};1' b.csv > c.csv
会把csv文件转换成:因此,现在如果应用命令:
将发生期望的改变。
它在旧格式中失败的合理原因是,当我们使用“read”命令读取值时,它会将
"a"
转换为"\"a\""
。因此,每次我追加答案时,它都会返回void answer。答案适用于任何类型的json格式。例如,如果json对象如下:
我们可以将命令更新为
'(.[] | select(.b == $k2) | .d.a) |= $k1'
。我没有其他方法张贴,但我感谢的帮助。谢谢乡亲(@峰和@弗拉瓦多纳)