JSONファイルのパスとキー値を印刷する方法

JSONファイルのパスとキー値を印刷する方法

各パスと値を印刷したいです。キー値を1行ずつ含むファイルです。次のような状況を考慮してそして、各行の値も追加できますか?使用しない場合別の方法がありますか?似たようなことを考えていた~のため。また、私がやろうとしていることについて技術的な用語がありますか?

$ 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"
]

複数行出力の1行の例:
"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

関連情報