【问题标题】:How can I incrementally generate JSON calling jq from bash repeatedly?如何从 bash 增量生成 JSON 调用 jq 重复?
【发布时间】:2021-10-01 18:37:42
【问题描述】:

是否有一些公认的使用 bash 和 jq 生成 JSON 文档的“最佳实践”?我有一个脚本来收集各种数据,并使用其他工具更容易进一步处理我想以 JSON 格式输出数据。所以我使用 jq 来确保所有引用等都正确完成,正如这个答案中所建议的那样:https://stackoverflow.com/a/48470227/75652。但是,我正在努力解决如何生成它而不是最后生成一个巨大的 jq 调用。例如。像


read foo <<<$(</path/to/some/oneliner/file)
jq -n --arg f $foo '{foo: $f}'

bar=$(some_command)
jq -n --arg b $bar '{bar: $b}'

将生成两个单独的对象(可以使用支持各种或多或少的非正式“JSON 流”格式的工具处理,包括 jq)而我想要一个对象,例如


{ "foo": SOMETHING, "bar": SOMETHING_ELSE }

但我不能通过多个 jq 调用来做到这一点,因为 jq 会抱怨不完整的 JSON 格式错误。

为了进一步增加一些复杂性,在某些情况下我需要生成嵌套的 JSON 结构。在像 python 这样的另一种语言中,我只是将所有数据放在一组嵌套字典中,然后最后将其转储到 JSON,但是 bash 中的嵌套字典似乎非常乏味..

【问题讨论】:

  • 为了进一步增加一些复杂性,在某些情况下我需要生成嵌套的 JSON 结构。有什么例子?
  • jq -n --arg f "$foo" --arg b "$bar" '{foo: $f, bar: $b}'?
  • “最后一点而不是一个巨大的呼叫”通常会适得其反。您调用的外部流程越不同,您在启动这些流程时消耗的开销就越多。更有效地减少它们的数量,或者 - 理想情况下 - 只有一个。
  • (在 bash 中嵌入 awk 也是如此:如果您可以将整个循环移动到 awk 中,而不是让 bash 每次通过循环时单独调用 awk,那就是 大大更快,通常是几个数量级;对于 jq 也是如此)。
  • @janneb 他所指的错误不是在您的jq 调用中引用$foo$bar 的扩展。正确方法见我之前的评论。

标签: json bash shell jq


【解决方案1】:

您可以为下一个 jq 命令保存和处理中间 JSON:

#!/usr/bin/env bash

read -r foo <a.txt

json="$(jq -n --arg f "$foo" '{foo: $f}')"


bar="$(pwd)"
jq -n --arg b "$bar" "$json"'+{bar: $b}'

# or alternatively
jq --arg b "$bar" '.bar=$b' <<<"$json"

【讨论】:

  • 抱怨$(pwd)代替$PWD
  • @CharlesDuffy 仅用于说明目的,只有一个命令可以产生合理可预测和简单的东西。当然$PWD 将是首选。
【解决方案2】:

当达到某种复杂性时(或者当我需要在转换之间从外部处理一些数据时),我通常最终会使用类似

的东西
jq --slurpfile foo <(
  
  # first inner shell script
  read foo <<<$(</path/to/some/oneliner/file)
  jq -n --arg f $foo '{foo: $f}'

) --slurpfile bar <(

  # second inner shell script
  bar=$(some_command)
  jq -n --arg b $bar '{bar: $b}'

) -n '$foo[0] + $bar[0]'

这样,最外层的 jq 调用可能仍然有自己的“真实”输入,并且内部调用在所有 bash 变量都在范围内时是相当可维护的。

【讨论】:

  • 它必须是--arg f "$foo" 带引号。同样--arg b "$bar"
  • 此外,某些版本的 bash 可能会因为 &lt;&lt;&lt;$var 而不是 &lt;&lt;&lt;"$var" 而出现行为异常,尽管这在当前版本中已修复。
【解决方案3】:

Q 使 $foo$bar 看起来可以预先计算, 在这种情况下,您可以用作模型:

jq -n --arg f "$foo" --arg b "$bar" '.foo = $f | .bar = $b' 

当然如果$foo的值很大的话,最好 使用面向文件的命令行使这些值对 jq 可用 选项,例如--slurpfile

如果某些值的计算取决于非常 大文件,然后多次调用 jq 可能是有意义的。在那里面 在这种情况下,对 jq 进行 N 次调用以编组这些值,然后进行一次 额外调用将​​它们组装成单个 JSON 对象(可能使用 'jq -s add') 看起来很合理。

Q 标题中建议的替代方案是 是创建一个调用 jq 的管道,例如:

  jq -n --argfile f <(some nasty stuff) '.foo = $f' |
    jq  --argfile b <(some more nasty stuff) '.bar = $b' | ...

最后,如果 $bar 以某种方式依赖于 $foo,那么如果该依赖 可以在 jq 程序中表示,您可以在底层阅读 使用更复杂的 jq 程序在一次 jq 调用中获取值。

【讨论】:

  • jq 手册不鼓励使用--argfile
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-04-21
  • 1970-01-01
  • 2021-04-01
  • 1970-01-01
  • 2020-07-11
  • 1970-01-01
相关资源
最近更新 更多