以下のテキストファイルがあります。
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行に印刷するように指示し、paste
JSONオブジェクト全体が各行の後に印刷されるようにします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
$j
pathname
input
このinput
関数は次の入力データを返します。この場合、JSON入力の代わりに「生の入力」を提供し、処理が開始されるとファイル全体が自動的に読み込まれるのを防ぎ、-R
がすべて有効であることを確認します。これは、「次の入力」がテキストファイルの次の縮小であることを意味します。-n
input.txt
input.txt
上記の効果は、JSONファイル内の各オブジェクトのinput.txt
新しいキー値として行を追加することです。pathname
input.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
キー値を抽出します。