テキストとJsonファイルをマージする

テキストとJsonファイルをマージする

以下のテキストファイルがあります。

AWSDynamoDB/01629227303395-c3801363/_started
AWSDynamoDB/01629227303395-c3801363/data/57sxfwx54y63xo46yhna6qgf3e.json.gz

以下のJSONファイルがあります。

{
    "TagSet": [test:tag]
}
{
    "TagSet": [foo:bar]
}

出力が次のように表示されるように、これらのファイルをマージしたいと思います。

    AWSDynamoDB/01629227303395-c3801363/_started       
{
            "TagSet": [test:tag]
        }
    AWSDynamoDB/01629227303395-c3801363/data/57sxfwx54y63xo46yhna6qgf3e.json.gz    
{
            "TagSet": [foo:bar]
        }

またはこれ。

   AWSDynamoDB/01629227303395-c3801363/_started       
                    "TagSet": [test:tag]
            
        AWSDynamoDB/01629227303395-c3801363/data/57sxfwx54y63xo46yhna6qgf3e.json.gz    
                    "TagSet": [foo:bar]
        

使ってみよう

paste input.txt output.json | pr -t -e24

しかし、それは私が探している結果を提供しません。

以下は、AWS CLIを実行したときに得られる出力です。

[cloudshell-user@ip-10-1-188-228 ~]$ aws s3api list-objects --bucket tesXXXXXnkins --query 'Contents[?LastModified<=`2021-09-07T00:00:00`].{Key:Key}' --output text | xargs -n 1 aws s3api get-object-tagging   --bucket testXXXXXkins --key
{
    "TagSet": []
}
{
    "TagSet": []
}
{
    "TagSet": []
}
{
    "TagSet": []
}
{
    "TagSet": []
}
{
    "TagSet": []
}
{
    "TagSet": []
}
{
    "TagSet": []
}
{
    "TagSet": []
}

この目標をどのように達成できますか?

答え1

次のようにいくつかの仮定をしましょう。

  • 正しい形式のJSONファイルのルートレベルにあるオブジェクトのリストに、1対1でマップされた改行で区切られた文字列のリストを含むファイルがあります。
  • 文字列リストの行とJSONオブジェクトリストのオブジェクトのペアを出力しようとしています(各ファイルに表示される順序に応じて)。
  • あなたの質問に示されているように、出力のインデントは関係ありません。

与えられた入力データ:

$ cat input.txt
AWSDynamoDB/01629227303395-c3801363/_started
AWSDynamoDB/01629227303395-c3801363/data/57sxfwx54y63xo46yhna6qgf3e.json.gz
$ cat input.json
{
  "TagSet": []
}
{
  "TagSet": [
    {
      "foo": "bar"
    }
  ]
}

使用jqそしてpaste(BashのようなANSI C引用スタイルをサポートするシェルで$'string')、次のように書くことができます。

$ jq -rc < input.json '.' | paste -d $'\n' input.txt -
AWSDynamoDB/01629227303395-c3801363/_started
{"TagSet":[]}
AWSDynamoDB/01629227303395-c3801363/data/57sxfwx54y63xo46yhna6qgf3e.json.gz
{"TagSet":[{"foo":"bar"}]}

この-cオプションは、jq各オブジェクトを1行に印刷するように指示し、pasteJSONオブジェクト全体が各行の後に印刷されるようにしますinput.txt

より多くの入力を使用すると、jq出力をきれいに印刷できます(再びBashを想定)。

$ readarray -t lines < input.txt
$ jq -r -s \
  'range($ARGS.positional | length) as $i | $ARGS.positional[$i], .[$i]' \
  --args "${lines[@]}" < input.json
AWSDynamoDB/01629227303395-c3801363/_started
{
  "TagSet": []
}
AWSDynamoDB/01629227303395-c3801363/data/57sxfwx54y63xo46yhna6qgf3e.json.gz
{
  "TagSet": [
    {
      "foo": "bar"
    }
  ]
}

fromの各行はシェル配列の要素input.txtとして読み込まれlines、次に渡された位置引数のリストに展開されますjq
この-sオプションは、各オブジェクトに対してフィルタ処理を一度実行するのではなく、オブジェクトのリストを配列にjq読み込みます。長さに応じて(input.json
n)、jqスクリプトは1以下を繰り返します。n使用範囲i索引付けと印刷のペアは、以下で提供されます。i最初の位置引数とi最初のJSONオブジェクトです。これはexp as $identifier | ...、式の各値に対して入力データ全体に対して右側のフィルタ()を実行する設定を使用して行われます(右側のフィルタで利用可能)。...exp$identifier

答え2

私もfra-sanと同じ仮定をしています。彼らの答えにつまり、次のような構造を持つよく構成されたJSONドキュメントがあります。

{"TagSet":[]}
{"TagSet":[{"foo":"bar"}]}

...JSON入力のオブジェクトと同じ行数のテキストファイルがあります。

AWSDynamoDB/01629227303395-c3801363/_started
AWSDynamoDB/01629227303395-c3801363/data/57sxfwx54y63xo46yhna6qgf3e.json.gz

より良い単語が必要な場合は、テキストファイルのパス名を名前付き新しいキーの下の対応するJSONオブジェクトに挿入して、最初のパス名がpathname最初のオブジェクトpathnameのキー値になるようにすることができます。

jq -Rn --slurpfile j input.json '$j[] | .pathname = input' input.txt

上記のコマンドは最初に既存のJSONドキュメントを配列input.jsonに読み込みます。次に、その配列の要素を繰り返します。つまり、JSONファイルのオブジェクトを繰り返し、関数の戻り値として値が提供される各要素のキーを作成します。jq$jpathnameinput

このinput関数は次の入力データを返します。この場合、JSON入力の代わりに「生の入力」を提供し、処理が開始されるとファイル全体が自動的に読み込まれるのを防ぎ、-Rがすべて有効であることを確認します。これは、「次の入力」がテキストファイルの次の縮小であることを意味します。-ninput.txtinput.txt

上記の効果は、JSONファイル内の各オブジェクトのinput.txt新しいキー値として行を追加することです。pathnameinput.json

出力は次のとおりです。

{
  "TagSet": [],
  "pathname": "AWSDynamoDB/01629227303395-c3801363/_started"
}
{
  "TagSet": [
    {
      "foo": "bar"
    }
  ],
  "pathname": "AWSDynamoDB/01629227303395-c3801363/data/57sxfwx54y63xo46yhna6qgf3e.json.gz"
}

その後、上記の内容をコマンドへの入力として使用して、埋め込みコンテンツを含むTagSetそのオブジェクトのパス名を抽出できます。{foo:"bar"}data.json

jq -r 'select(any(.TagSet[]; . == {foo:"bar"})).pathname' data.json

その後、データを読み取り、TagSet配列要素を含むオブジェクトを選択します{foo:"bar"}。これらのオブジェクトからpathnameキー値を抽出します。

関連情報