我有一个如下所示的文本文件
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 文件根级别的对象列表;
- 您想要输出对应的(基于它们在每个文件中出现的顺序)一对字符串列表中的一行和 JSON 对象列表中的一个对象;
- 输出的缩进(如您的问题所示)不相关;
给定输入数据:
$ cat input.txt
AWSDynamoDB/01629227303395-c3801363/_started
AWSDynamoDB/01629227303395-c3801363/data/57sxfwx54y63xo46yhna6qgf3e.json.gz
$ cat input.json
{
"TagSet": []
}
{
"TagSet": [
{
"foo": "bar"
}
]
}
使用jq
并且paste
(在支持 ANSI C 引用样式的 shell 中$'string'
,例如 Bash),您可以编写:
$ 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
在一行上打印每个对象,确保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
shell 数组的一个元素,然后将其扩展为传递给 的位置参数列表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
入jq
数组$j
。然后,它遍历该数组的元素,即遍历 JSON 文件的对象,并为每个元素创建一个pathname
键,该键的值由函数的返回值给出input
。
该input
函数返回下一个输入数据。在这种情况下,我们确保-R
和-n
都有效,分别为我们提供“原始输入”而不是 JSON 输入,并避免input.txt
在处理开始后自动读取整个文件。这意味着“下一个输入”是input.txt
我们的文本文件的后续行。
上面的效果是为 JSON 文件中的每个对象添加一行 frominput.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
键的值。