2

假设我有这个 json

{
  "sha256:0085b5379bf1baeb4a430128782440fe636938aa739f6a5ecc4152a22f19b08b": {
    "imageSizeBytes": "596515805",
    "layerId": "",
    "mediaType": "application/vnd.docker.distribution.manifest.v2+json",
    "tag": [
      "python-3-toolchain-0.1.2"
    ],
    "timeCreatedMs": "1564631021992",
    "timeUploadedMs": "1564631067325"
  },
  "sha256:1ec7631f74a3d6d37bf9194c13854f33315260ae1f27347263dd0a8974ee82bb": {
    "imageSizeBytes": "513574770",
    "layerId": "",
    "mediaType": "application/vnd.docker.distribution.manifest.v2+json",
    "tag": [
      "python-2-toolchain-latest"
    ],
    "timeCreatedMs": "1535447023647",
    "timeUploadedMs": "1535447042373"
  }
}

我想选择带有特定标签的图像信息(以及 sha256 摘要)。示例:我只想选择tag == "python-2-toolchain-latest",所以它打印这个 json (使用 json 重新格式化)

 {
    "digest": "sha256:1ec7631f74a3d6d37bf9194c13854f33315260ae1f27347263dd0a8974ee82bb",
    "imageSizeBytes": "513574770",
    "layerId": "",
    "mediaType": "application/vnd.docker.distribution.manifest.v2+json",
    "tag": [
      "python-2-toolchain-latest"
    ],
    "timeCreatedMs": "1535447023647",
    "timeUploadedMs": "1535447042373"
  }

我尝试了各种方法,并被困在如何引用 sha256 关键信息上。

4

4 回答 4

1

一个可能的jq程序来实现你的目标:

# Embed the final result into an array to get a valid JSON output
[
    # Convert the input object into a list of { key, value } objects
    to_entries[]

    # Keep only the objects that contain the desired tag
    # The .tag field may contain multiple tags and the desired one can be at any position
    | select(.value.tag | contains(["python-2-toolchain-latest"]))

    # Add the key into the value object into the .digest property
    | .value.digest = .key

    # Keep only the values (the modified objects)
    | .value

# That's all, folks
]

在线尝试!

于 2019-08-21T18:58:54.770 回答
0

这是一个简单明了但有效的解决方案:

keys_unsorted[] as $k
| .[$k] as $value
| select($value.tag[0] ==  "python-2-toolchain-latest")
| {digest: $k} + $value

于 2019-08-01T15:50:12.417 回答
0

这是我的工作。我假设标签数组可以包含多个条目......

.
|to_entries[]
|.key as $k
|.value as $v
|.value.tag[]
|select(.=="python-2-toolchain-latest")
[ { "digest": ($k) }, $v ] | add

看到高峰答案后,我更喜欢这样的最后一行:

[ { "digest": ($k) } + $v ]

如果标签可以出现两次,那么这将输出相同的记录两次。必须有更好的方法来简单地检查“python-2-toolchain-latest”是否在 tag[] 数组中。我的 jq foo 不够强大。

于 2019-08-01T18:19:07.280 回答
0

我会用

.
| to_entries
| .[]
| select(.value.tag | contains(["python-2-toolchain-latest"]))
| { digest: .key } + .value
  • 我将您的示例数据放在我命名的文件中pratama-1.json
  • 我运行了以下命令并得到了这个输出。
    $ jq '. | to_entries | .[] | select(.value.tag | contains(["python-2-toolchain-latest"])) | { digest: .key } + .value' pratama-1.json
    {
      "digest": "sha256:1ec7631f74a3d6d37bf9194c13854f33315260ae1f27347263dd0a8974ee82bb",
      "imageSizeBytes": "513574770",
      "layerId": "",
      "mediaType": "application/vnd.docker.distribution.manifest.v2+json",
      "tag": [
        "python-2-toolchain-latest"
      ],
      "timeCreatedMs": "1535447023647",
      "timeUploadedMs": "1535447042373"
    }
    

打破这个

您可以将jq程序视为类似于sh管道,除了: - 使用sh(or bash),管道的每个阶段(即 s 之间的每个命令|)都有一个字节流(通常只是文本)作为其输入和输出;- 使用jq,每个阶段都有一个JSON 值流作为其输入和输出。

  1. 最简单的jq程序很简单.
    • 如果输入是 JSON 值true,则输出是true.
    • 如果输入是 JSON 值[ true, 3.1416, "foo" ](数组值),则输出相同。
    • 如果输入是三个 JSON 值true3.1416"foo"(一个布尔值、一个数字和一个字符串),那么三个输出将是那个布尔值、那个数字和那个字符串。
  2. 在我的脚本的开头,.just 代表输入值,在这种情况下,它是您在问题中包含的 JSON 对象。
  3. 下一阶段是to_entries
    • 它将 JSON 对象转换为 JSON 对象的 JSON 数组。对于像这样的输入:
      {
        "a": 3.1416,
        "b": false
      }
      
      成这样的数组:
      [
        {
          "key": "a",
          "value": 3.1416
        },
        {
          "key": "b",
          "value": false
        }
      ]
      
  4. 下一个阶段是.[],这是一个jq将一个 JSON 值转换为多个值的运算符:
    • 如果输入是单个 JSON 数组,例如[ true, 3.1416, "foo" ],则三个输出是 JSON 值true3.1416"foo"
    • 在我们的例子中,它围绕所有这些键值对象展开 JSON 数组,因此我们可以输出多个值而不是一个 JSON 数组输出值。
  5. 下一阶段是select(…)
    • 对于每个输入值,它计算括号中的表达式,如果表达式为真,则将该输入作为输出“传递”。
    • 例如,对于三个输入true3.1416"foo"select(type == "string") 将只有一个输出:字符串"foo"
    • select(…)有两个输入:
      1. 一个 JSON 对象{ "key": "sha256:008…", "value": { "imageSizeBytes": … } }
      2. 一个 JSON 对象{ "key" :"sha256:1ec…", "value": { "imageSizeBytes": … } }
    • 在我的内部select(…),我使用了一个子表达式,它本身就是一个jq管道.value.tag | contains(["python-2-toolchain-latest"])::
      1. 第一部分产生每个对象中.value.tag带有键的字段的值。"tag"对于您的示例数据,每个值都是一个 JSON 数组。
      2. 如果其参数 JSON 数组中的所有值都是该输入 JSON 数组值的成员,则该contains([…])部分对输入 JSON 数组 值进行赋值。 true[…]
        • 一些例子
        $ jq '. | contains([ "foo" ])' <<< '[ true, 3.1416, "foo" ]'
        true
        $ jq '. | contains([ "foo", true ])' <<< '[ true, 3.1416, "foo" ]'
        true
        $ jq '. | contains([ "foo", true, null ])' <<< '[ true, 3.1416, "foo" ]'
        false
        $ jq '. | contains([ "foo", true, false ])' <<< '[ true, 3.1416, "foo" ]'
        false
        $ jq '. | contains([ "foo", true, null ])' <<< '[ true, 3.1416, "foo" ]'
        false
        
    • 因此,对于每个输入 JSON 对象,我的表达式select(…)计算为,该对象具有一个以JSON 子对象值命名的键,该键具有一个以 JSON 数组值命名的键,该数组值包含一个具有 JSON 字符串值“python-2-toolchain”的元素-最新的”。true"value""tag"
    • 对于其中表达式为 的每个输入select(…)true该输入值成为输出值之一。
    • 对于您的示例数据,这只是第二个子对象:{ "key": "sha256:1ec…", "value": { … } }.
  6. 我的管道的最后一个阶段是一个jq看起来像 JSON 对象的表达式。
    • { digest: .key }表示对于每个输入值,输出一个 JSON 对象值:
      • 一个名为"digest" AND的键
      • 该键的值应该是与输入 JSON 对象名为 的键关联的值"key"
      • 由于我们的输入是 JSON 对象{ "key": "sha256:1ec…", … },这将为我们提供输出 JSON 对象{ "digest": "sha256:1ec…" }
    • 但我们也想在输出 JSON 对象中添加其他内容:我们想添加与"value"输入对象中的键关联的 JSON 对象值。我们通过添加+ .value.
    • jq +与 JSON 对象值一起使用时,运算符将其操作数 JSON 对象“合并”为单个输出 JSON 对象,例如{ "a": true } + { "b": 3.1416 }yield { "a": true, "b": 3.1416 }
于 2019-11-06T06:33:21.457 回答