【问题标题】:How to merge JSON arrays from multiple files via jq with order preserved如何通过 jq 合并来自多个文件的 JSON 数组并保留顺序
【发布时间】:2018-12-01 01:38:11
【问题描述】:

我正在尝试设置 JSON 配置文件的层次结构,其中可以在多个级别覆盖默认值。每个文件都是一组键/值对。其中有许多是按功能按非字母顺序组织的。

我找到了一种方法来获得我想要的逻辑结果,但是它是按字母顺序排序的,并且由于预期参数的数量,用户很难清楚/快速地查看集合是否是什么他们想要在使用它之前。

有没有办法执行这种合并,替换匹配键上的值并保留顺序?

我有这些文件:

default.json:

[
  { "ParameterKey": "FirstStackName",  "ParameterValue": "Production-App-Database" },
  { "ParameterKey": "SecondStackName", "ParameterValue": "Production-Directory" },
  { "ParameterKey": "ThirdStackName",  "ParameterValue": "Production-VPC" },
  { "ParameterKey": "FourthStackName", "ParameterValue": "AMIFunctions" },
  { "ParameterKey": "FifthKeyName",    "ParameterValue": "administrator" },
  { "ParameterKey": "SixthUserName",   "ParameterValue": "admin" },
  { "ParameterKey": "SeventhPassword", "ParameterValue": "" }
]

环境.json:

[
  { "ParameterKey": "FirstStackName",  "ParameterValue": "Development-App-Database" },
  { "ParameterKey": "SecondStackName", "ParameterValue": "Development-Directory" },
  { "ParameterKey": "ThirdStackName",  "ParameterValue": "Development-VPC" },
  { "ParameterKey": "FifthKeyName",    "ParameterValue": "developer" }
] 

user.json:

[
  { "ParameterKey": "FifthKeyName",    "ParameterValue": "jdoe" }
] 

secure.json:

[
  { "ParameterKey": "SeventhPassword", "ParameterValue": "secretvalue" }
] 

如果我运行这个:

jq -s '.[3] + .[2] + .[1] + .[0] | unique_by(.ParameterKey)' default.json environment.json user.json secure.json

我得到了一些有用的东西:

[
  { 
    "ParameterKey": "FifthKeyName",
    "ParameterValue": "jdoe"
  },
  {
    "ParameterKey": "FirstStackName",
    "ParameterValue": "Development-App-Database"
  },
  {
    "ParameterKey": "FourthStackName",
    "ParameterValue": "AMIFunctions"
  },
  {
    "ParameterKey": "SecondStackName",
    "ParameterValue": "Development-Directory"
  },
  {
    "ParameterKey": "SeventhPassword",
    "ParameterValue": "secretvalue"
  },
  {
    "ParameterKey": "SixthUserName",
    "ParameterValue": "admin"
  },
  {
    "ParameterKey": "ThirdStackName",
    "ParameterValue": "Development-VPC"
  }
]

但是(想象一下 60 个参数)它不容易被扫描为正确的,而我想要的是:

[
  { "ParameterKey": "FirstStackName",  "ParameterValue": "Development-App-Database" },
  { "ParameterKey": "SecondStackName", "ParameterValue": "Development-Directory" },
  { "ParameterKey": "ThirdStackName",  "ParameterValue": "Development-VPC" },
  { "ParameterKey": "FourthStackName", "ParameterValue": "AMIFunctions" },
  { "ParameterKey": "FifthKeyName",    "ParameterValue": "jdoe" },
  { "ParameterKey": "SixthUserName",   "ParameterValue": "admin" },
  { "ParameterKey": "SeventhPassword", "ParameterValue": "secretvalue" }
] 

【问题讨论】:

  • default.json 是否保证拥有在其他文件中找到的键的超集?
  • 可以做到。不确定是否有替代方案。如果您没有猜到,这是将参数数组传递给 AWS CloudFormation 模板。那是在 YAML 中,并且具有完整的默认设置。因此,理想情况下,我只想传入环境、用户和安全覆盖,因为默认值在模板本身中。但是,不要认为这很容易做到。
  • 我没有猜到——我构建了一个在物理硬件上发布的产品,并且没有任何使用 CloudFormation 的经验。也就是说,您所描述的内容对我来说似乎并不难,但我需要一个合适的复制器来测试问题中提供的内容是否不足以准确代表真实情况。

标签: json bash jq


【解决方案1】:

unique_by 需要排序,所以最简单的方法是使用INDEX(大写):

[INDEX(inputs[]; .ParameterKey)[]]

我在这里使用了inputs 来避免 -s 选项的所有缺点,但请记住改用 -n 选项。

如果你的 jq 没有 INDEX,你可以使用这个 def:

def INDEX(s; f):
  reduce s as $x  (null; .[$x|f] = $x );

【讨论】:

    【解决方案2】:

    简单的做法是构建一个从键到值的映射(依次组合所有输入源),然后返回并重新处理default.json,应用生成的映射。

    jq -n --slurpfile template default.json '
    # generate an unordered key:value dictionary
    ([inputs | .[] | {(.ParameterKey): (.ParameterValue)}] | add) as $map |
    
    # apply those pairs to the template to get its ordering
    [ $template[0][] | {"ParameterKey": (.ParameterKey), "ParameterValue": ($map[.ParameterKey])} ]
    
    ' default.json environment.json user.json secure.json
    

    ...正确输出:

    [
      {
        "ParameterKey": "FirstStackName",
        "ParameterValue": "Development-App-Database"
      },
      {
        "ParameterKey": "SecondStackName",
        "ParameterValue": "Development-Directory"
      },
      {
        "ParameterKey": "ThirdStackName",
        "ParameterValue": "Development-VPC"
      },
      {
        "ParameterKey": "FourthStackName",
        "ParameterValue": "AMIFunctions"
      },
      {
        "ParameterKey": "FifthKeyName",
        "ParameterValue": "jdoe"
      },
      {
        "ParameterKey": "SixthUserName",
        "ParameterValue": "admin"
      },
      {
        "ParameterKey": "SeventhPassword",
        "ParameterValue": "secretvalue"
      }
    ]
    

    ...保留default.json 的订单。


    如果您坚持就这样使用空格,一种方法是通过以下管道输出上述内容:

    #!/usr/bin/env bash
    shopt -s extglob
    pieces=( )
    while read -r line; do
      case $line in
        "["|"]")       printf '%s\n' "$line";;
        *(' ')"}"?(,)) printf '%2s %-35s %s %2s\n' "${pieces[@]}" "$line"; pieces=( );;
        *)             pieces+=( "$line" )
      esac
    done
    

    以上注意只更改空格,并且不识别除换行符以外的任何分隔符;因此,其输出应始终在语义上与其输入相同。请参阅 https://ideone.com/EI0RuJ 作为此代码在实践中工作的演示,输出为:

    [
     { "ParameterKey": "FirstStackName",   "ParameterValue": "Development-App-Database" },
     { "ParameterKey": "SecondStackName",  "ParameterValue": "Development-Directory" },
     { "ParameterKey": "ThirdStackName",   "ParameterValue": "Development-VPC" },
     { "ParameterKey": "FourthStackName",  "ParameterValue": "AMIFunctions" },
     { "ParameterKey": "FifthKeyName",     "ParameterValue": "jdoe" },
     { "ParameterKey": "SixthUserName",    "ParameterValue": "admin" },
     { "ParameterKey": "SeventhPassword",  "ParameterValue": "secretvalue"  }
    ]
    

    【讨论】:

    • 这太棒了!非常接近我正在寻找的内容,并且没有我期望的算法代码。我确实通过一些 sed 命令来运行它以使其更接近:(上面的代码)| sed -e '/{$/N;s/\n //' -e '/^ {.*,$/N;s/\n //g' -e '/^ {.*$/N; s/\n //' - 现在只缺少列对齐。
    • 我非常不喜欢使用语法不了解的工具来修改 JSON,但如果你必须,答案就修改了。
    • (另一件事是,包括格式化和 jq 工作确实使这个问题分叉,使其不再是“这里是特定和狭窄问题的规范答案”的知识库中的一个条目 - - 我们为之努力 - 并且朝着成为“请为我编写代码”的问题而努力,我们通常根本不欢迎)。
    • Charles - 感谢您加倍努力,因为我意识到我的请求可能有点越界了,我请求格式化 JSON 输出并且可能应该在“sed”组中提出这个问题。我本可以像您提供的那样编写脚本(谢谢),但希望在 sed 或 awk 中有一种我不知道的非算法方法。而且,我认为其他人可能会对对齐 JSON 键/值数组的方法感兴趣,因为它很常见。
    • 另外,我不知道有一个支持 JSON 语法的工具,它允许折叠默认的缩进格式,虽然标准,但往往会产生长而窄的输出,这对人类来说并不容易读作当我要求的某些行组合完成时。例如,来自 AWS 的大多数企业级 CloudFormation JSON 示例都以这种方式组合行来提高可读性。如果您知道可以通过某种类型的配置文件组合 JSON 行的工具,我很乐意使用它!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-11-01
    • 2023-03-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-06-28
    相关资源
    最近更新 更多