为什么 jq 的 slurp 不能处理 here-strings 和其他文件的组合?
Why can't jq's slurp handle a combination of here-strings and other files?
我想将文件中的一些 json 与运行时生成的一些 json 合并。如果传递给它的所有文件都是here-strings,或者系统中的文件,jq似乎没有困难。但是如果我尝试混合文件类型,这里的字符串似乎会被忽略,请参见下面的代码片段:
两个普通文件:
bash-4.2# echo '{"key":0}' > zero
bash-4.2# echo '{"key":1}' > one
bash-4.2# jq --slurp add zero one
{
"key": 1
}
普通文件和here-string(结果中只出现普通文件!):
bash-4.2# jq --slurp add zero <<< '{"key":1}'
{
"key": 0
}
这里-先是字符串,后是普通文件(结果只出现普通文件!):
bash-4.2# jq --slurp add <<< '{"key":0,"anotherkey":2}' one
{
"key": 1
}
单个此处字符串(工作正常):
bash-4.2# jq --slurp add <<< '{"key":0}'
{
"key": 0
}
这里有两个字符串(工作正常): 编辑:输出具有误导性,这里发生了其他事情。
bash-4.2# jq --slurp add <<< '{"key":0}' <<< '{"key":1}'
{
"key": 1
}
我怀疑 jq 工作得很好,我不知道 bash 如何解析这里的字符串。但是,我将如何调试它以提高我的理解?
注意:一个非常简单的解决方法是评估我的运行时 json 并生成一个文件,然后如上所述合并这两个文件。我真的很想知道为什么上面的粗体示例没有产生我期望的结果。
here-string 构造只是重定向标准输入。如果您以接收文件名参数的方式调用标准输入,则需要单独告诉 jq
到 read 标准输入。 事实上的标准方法是指定-
作为输入(伪)文件名。
我相信您的一个测试用例实际上并没有起作用,只是看起来起作用了,因为输入数据的构造是空操作。
一个想法是使用进程替换,本质上,它提供 jq
它可以使用的(临时)文件描述符。
使用awk
演示文件描述符的想法:
$ awk '{print FILENAME}' <(echo 'abc')
/dev/fd/63
用您的几个示例进行演示:
$ jq --slurp add zero <(echo '{"key":1}')
{
"key": 1
}
$ jq --slurp add zero <(echo '{"keyx":1}')
{
"key": 0,
"keyx": 1
}
$ jq --slurp add <(echo '{"key":0,"anotherkey":2}') one
{
"key": 1,
"anotherkey": 2
}
$ jq --slurp add <(echo '{"key":0}') <(echo '{"key":1}')
{
"key": 1
}
$ jq --slurp add <(echo '{"key":0}') <(echo '{"keyx":1}')
{
"key": 0,
"keyx": 1
}
看完评论,我的理解是:
<<<
首先由 shell 评估并重定向标准输入。如果 jq
在过滤器之后没有收到位置参数,它会从标准输入中读取。因此所有这些陈述都是等价的:
echo "{}" | jq --slurp add
<<< {} jq --slurp add
jq <<< {} --slurp add
jq --slurp <<< {} add
jq --slurp add <<< {}
如果 jq
确实在过滤器之后接收到位置参数,它会将它们解释为文件名。它遵守将 -
视为标准输入的惯例。
bash-4.2# echo '{"one":1,"two":1}' > first
bash-4.2# echo '{"three":3}' > third
bash-4.2# jq --slurp add first - third <<< '{"two":2}'
{
"one": 1,
"two": 2,
"three": 3
}
我想将文件中的一些 json 与运行时生成的一些 json 合并。如果传递给它的所有文件都是here-strings,或者系统中的文件,jq似乎没有困难。但是如果我尝试混合文件类型,这里的字符串似乎会被忽略,请参见下面的代码片段:
两个普通文件:
bash-4.2# echo '{"key":0}' > zero
bash-4.2# echo '{"key":1}' > one
bash-4.2# jq --slurp add zero one
{
"key": 1
}
普通文件和here-string(结果中只出现普通文件!):
bash-4.2# jq --slurp add zero <<< '{"key":1}'
{
"key": 0
}
这里-先是字符串,后是普通文件(结果只出现普通文件!):
bash-4.2# jq --slurp add <<< '{"key":0,"anotherkey":2}' one
{
"key": 1
}
单个此处字符串(工作正常):
bash-4.2# jq --slurp add <<< '{"key":0}'
{
"key": 0
}
这里有两个字符串(工作正常): 编辑:输出具有误导性,这里发生了其他事情。
bash-4.2# jq --slurp add <<< '{"key":0}' <<< '{"key":1}'
{
"key": 1
}
我怀疑 jq 工作得很好,我不知道 bash 如何解析这里的字符串。但是,我将如何调试它以提高我的理解?
注意:一个非常简单的解决方法是评估我的运行时 json 并生成一个文件,然后如上所述合并这两个文件。我真的很想知道为什么上面的粗体示例没有产生我期望的结果。
here-string 构造只是重定向标准输入。如果您以接收文件名参数的方式调用标准输入,则需要单独告诉 jq
到 read 标准输入。 事实上的标准方法是指定-
作为输入(伪)文件名。
我相信您的一个测试用例实际上并没有起作用,只是看起来起作用了,因为输入数据的构造是空操作。
一个想法是使用进程替换,本质上,它提供 jq
它可以使用的(临时)文件描述符。
使用awk
演示文件描述符的想法:
$ awk '{print FILENAME}' <(echo 'abc')
/dev/fd/63
用您的几个示例进行演示:
$ jq --slurp add zero <(echo '{"key":1}')
{
"key": 1
}
$ jq --slurp add zero <(echo '{"keyx":1}')
{
"key": 0,
"keyx": 1
}
$ jq --slurp add <(echo '{"key":0,"anotherkey":2}') one
{
"key": 1,
"anotherkey": 2
}
$ jq --slurp add <(echo '{"key":0}') <(echo '{"key":1}')
{
"key": 1
}
$ jq --slurp add <(echo '{"key":0}') <(echo '{"keyx":1}')
{
"key": 0,
"keyx": 1
}
看完评论,我的理解是:
<<<
首先由 shell 评估并重定向标准输入。如果 jq
在过滤器之后没有收到位置参数,它会从标准输入中读取。因此所有这些陈述都是等价的:
echo "{}" | jq --slurp add
<<< {} jq --slurp add
jq <<< {} --slurp add
jq --slurp <<< {} add
jq --slurp add <<< {}
如果 jq
确实在过滤器之后接收到位置参数,它会将它们解释为文件名。它遵守将 -
视为标准输入的惯例。
bash-4.2# echo '{"one":1,"two":1}' > first
bash-4.2# echo '{"three":3}' > third
bash-4.2# jq --slurp add first - third <<< '{"two":2}'
{
"one": 1,
"two": 2,
"three": 3
}