Hea*_*ery 18 pipe io-redirection jq
jq
当输出被重定向时需要一个显式过滤器的问题在整个网络上都有讨论。但是如果jq
是管道链的一部分,我无法重定向输出,即使在使用显式过滤器时也是如此。
考虑:
touch in.txt
tail -f in.txt | jq '.f1'
# in a different terminal:
echo '{"f1":1,"f2":2}' >> in.txt
echo '{"f1":3,"f2":2}' >> in.txt
Run Code Online (Sandbox Code Playgroud)
正如预期的那样,jq
命令的原始终端中的输出是:
1
3
Run Code Online (Sandbox Code Playgroud)
但是,如果我在jq
命令的末尾添加任何类型的重定向或管道,输出将变得无声:
rm in.txt
touch in.txt
tail -f in.txt | jq '.f1' | tee out.txt
# in a different terminal:
echo '{"f1":1,"f2":2}' >> in.txt
echo '{"f1":3,"f2":2}' >> in.txt
Run Code Online (Sandbox Code Playgroud)
第一个终端中没有输出,out.txt 为空。
我已经尝试了数百种变体,但这是一个难以捉摸的问题。唯一的解决办法我发现,通过发现mosquitto_sub
和东西网(这是我在那里也发现了这个问题),是包尾,并在shell脚本JQ功能:
#!/bin/bash
tail -f $1 | while IFS='' read line; do
echo $line | jq '.f1'
done
Run Code Online (Sandbox Code Playgroud)
然后:
./tail_and_jq.sh | tee out.txt
# in a different terminal:
echo '{"f1":1,"f2":2}' >> in.txt
echo '{"f1":3,"f2":2}' >> in.txt
Run Code Online (Sandbox Code Playgroud)
果然,输出出现了:
1
3
Run Code Online (Sandbox Code Playgroud)
这是jq
通过 Homebrew 安装的最新版本:
$ echo $SHELL
/bin/bash
$ jq --version
jq-1.5
$ brew install jq
Warning: jq 1.5_3 is already installed and up-to-date
Run Code Online (Sandbox Code Playgroud)
这是jq
我对管道链的理解或理解中的(很大程度上未记录的)错误吗?
Kus*_*nda 28
jq
当它的标准输出通过管道传输时,它的输出被缓冲。
要请求jq
在每个对象之后刷新其输出缓冲区,请使用其--unbuffered
选项,例如
tail -f in.txt | jq --unbuffered '.f1' | tee out.txt
Run Code Online (Sandbox Code Playgroud)
从jq
手册:
--unbuffered
在打印每个 JSON 对象后刷新输出(如果您将慢速数据源输送到其他地方
jq
并将jq
输出输送到其他地方,则很有用)。
您在这里看到的是 C stdio 缓冲在起作用。它会将输出存储在缓冲区中,直到达到某个限制(可能是 512 字节,或 4KB 或更大),然后一次性发送所有内容。
如果 stdout 连接到终端,此缓冲会自动禁用,但是当它连接到管道时(例如在您的情况下),它将启用此缓冲行为。
禁用/控制缓冲的常用方法是使用该setvbuf()
函数(有关更多详细信息,请参阅此答案),但这需要在其jq
自身的源代码中完成,因此可能对您来说不实用......
有一个解决方法......(一个黑客,有人可能会说。)有一个名为“unbuffer”的程序,它与“expect”一起分发,可以创建一个伪终端并将其连接到程序。因此,即使jq
仍在写入管道,它也会认为它正在写入终端,并且缓冲效果将被禁用。
安装“expect”包,它应该带有“unbuffer”,如果你还没有它......例如,在Debian(或Ubuntu)上:
$ sudo apt-get install expect
Run Code Online (Sandbox Code Playgroud)
然后你可以使用这个命令:
$ tail -f in.txt | unbuffer -p jq '.f1' | tee out.txt
Run Code Online (Sandbox Code Playgroud)
有关“unbuffer”的更多详细信息,另请参阅此答案,您也可以在此处找到手册页。