合并文本和 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 文件根级别的对象列表;
  • 您想要输出对应的(基于它们在每个文件中出现的顺序)一对字符串列表中的一行和 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被读入linesshell 数组的一个元素,然后将其扩展为传递给 的位置参数列表jq
-s选项将jq对象列表读取到input.json数组中,而不是为每个对象执行一次过滤程序。
根据长度(n) 的位置参数数组,jq脚本迭代1n范围使用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.jsonjq数组$j。然后,它遍历该数组的元素,即遍历 JSON 文件的对象,并为每个元素创建一个pathname键,该键的值由函数的返回值给出input

input函数返回下一个输入数据。在这种情况下,我们确保-R-n都有效,分别为我们提供“原始输入”而不是 JSON 输入,并避免input.txt在处理开始后自动读取整个文件。这意味着“下一个输入”是input.txt我们的文本文件的后续行。

上面的效果是为 JSON 文件中的每个对象添加一行 frominput.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键的值。

相关内容