如何打印JSON文件的路径和键值

如何打印JSON文件的路径和键值

我想打印 a 的每个路径和值逐行包含键值的文件。鉴于以下情况,是否也可以添加每行的值?如果不使用还有别的办法吗?我在想一些类似于为了。另外,对于我想要做的事情有一个技术术语吗?

$ cat short.json | jq '.'
{
  "Reservations": [
    {
      "Groups": [],
      "Instances": [
        {
          "ImageId": "ami-a",
          "InstanceId": "i-a",
          "InstanceType": "t2.micro",
          "KeyName": "ubuntu"
        }
      ]
    }
  ]
}
$ cat short.json | jq -r '[paths | map(.|tostring) | join(".")]'
[
  "Reservations",
  "Reservations.0",
  "Reservations.0.Groups",
  "Reservations.0.Instances",
  "Reservations.0.Instances.0",
  "Reservations.0.Instances.0.ImageId",
  "Reservations.0.Instances.0.InstanceId",
  "Reservations.0.Instances.0.InstanceType",
  "Reservations.0.Instances.0.KeyName"
]

多行输出中的单行示例:
"Reservations.0.Instances.0.ImageId": "ami-a",

如果输出可以格式化以用于以下用途,那就太好了使用复制和粘贴,可以使用 linux cut 轻松分离值:

'.Reservations[].Instances[].ImageId': "ami-a" 
$ cat short.json | jq -r '.Reservations[].Instances[].ImageId'
ami-a

答案1

我对此不太了解,jq但我在互联网上发现了这一点,我认为它适用于您的情况:

剪切和粘贴版本:

jq -r 'paths(scalars | true) as $p  | [ ( [ $p[] | tostring ] | join(".") ), ( getpath($p) | tojson )] | join(": ")' short.json 

易于阅读的版本:

jq -r '
paths(scalars | true) as $p
  | [ ( [ $p[] | tostring ] | join(".") )
    , ( getpath($p) | tojson )
    ]
  | join(": ")
' short.json

结果:

Reservations.0.Instances.0.ImageId: "ami-a"
Reservations.0.Instances.0.InstanceId: "i-a"
Reservations.0.Instances.0.InstanceType: "t2.micro"
Reservations.0.Instances.0.KeyName: "ubuntu"

因为我想要奖励积分,所以sed你可以使用以下技巧来获得你想要的输出:

... | sed "s/^/\'./; s/:/\':/; s/\.0/[]/g"

哪个输出:

'.Reservations[].Instances[].ImageId': "ami-a"
'.Reservations[].Instances[].InstanceId': "i-a"
'.Reservations[].Instances[].InstanceType': "t2.micro"
'.Reservations[].Instances[].KeyName': "ubuntu"

答案2

使用以下jq表达式,我们确保输出的键和值部分都是有效的 JSON(如果是字符串,则进行编码并加引号;如果是布尔值、数字或 则不加引号null)。我创建了一个辅助函数kv_to_str来格式化键值字符串,只是为了便于阅读:

def kv_to_str($k; $v): "\($k): \($v)";

paths(scalars | true) as $p |
    kv_to_str(
        $p | join(".") | tojson;
        getpath($p) | tojson
    )

对您的数据进行测试:

$ jq -r 'def kv_to_str($k;$v): "\($k): \($v)"; paths(scalars|true) as $p | kv_to_str($p|join(".")|tojson; getpath($p)|tojson)' file
"Reservations.0.Instances.0.ImageId": "ami-a"
"Reservations.0.Instances.0.InstanceId": "i-a"
"Reservations.0.Instances.0.InstanceType": "t2.micro"
"Reservations.0.Instances.0.KeyName": "ubuntu"

为了获得可用作jq查询每个值的表达式的内容,我们可以进行一些较小的调整,这样就不用像"Reservations.0.Instances.0.ImageId"我们那样创建键了.["Reservations"][0]["Instances"][0]["ImageId"]。请注意,我们将零保留在那里,这使我们能够为数组元素生成更具体的键。

def kv_to_str($k; $v): "\($k): \($v)";

paths(scalars | true) as $p |
    kv_to_str(
        "." + ($p | map([.] | tojson) | join(""));
        getpath($p) | tojson
    )

密钥是通过获取路径的每个部分、将其放入[...]并将其转换为 JSON 来生成的(字符串将被加引号,而整数索引将保持不加引号)。然后我们将各个部分连接起来并在前面添加一个点。

测试:

$ jq -r 'def kv_to_str($k;$v): "\($k): \($v)"; paths(scalars|true) as $p | kv_to_str("." + ($p|map([.]|tojson)|join("")); getpath($p)|tojson)' file
.["Reservations"][0]["Instances"][0]["ImageId"]: "ami-a"
.["Reservations"][0]["Instances"][0]["InstanceId"]: "i-a"
.["Reservations"][0]["Instances"][0]["InstanceType"]: "t2.micro"
.["Reservations"][0]["Instances"][0]["KeyName"]: "ubuntu"
$ jq -r '.["Reservations"][0]["Instances"][0]["InstanceType"]' file
t2.micro

相关内容