以下代码是我目前情况的简化版本。我有一个JSON日志源,我不断地获取并使用
puts
写入标准输出流。#!/usr/bin/env ruby
require "json"
loop do
puts({ value: "foobar" }.to_json)
sleep 1
end
我希望能够以Unix管道的方式将此脚本的输出传输到 jq
进行进一步处理。在保持“流”友好性的同时,如下运行以上代码:
./my_script | jq
结果为空。然而,如果我在sleep
调用后加上一个exit
语句,输出就按预期通过管道发送到jq
。我能够通过在puts
调用之后调用$stdout.flush
来解决这个问题。虽然现在它能正常工作了,但我不确定为什么。$stdout.sync
默认设置为true
(参见IO#sync
)。在我的看法中,如果启用了同步,Ruby应该不会进行任何输出缓冲,因此不应需要调用$stdout.flush
——但是实际情况却并非如此。
我的后续问题是关于使用tail
而非jq
。在我看来,我应该能够以同样的方式将文本流管道传入tail
,但无论是否调用$stdout.flush
,两种方法都不起作用——输出为空。
tail
命令可以显示输入内容的最后N行。如果输入内容还没有结束,tail
就无法决定要显示什么。 - mrzasaSTDOUT.sync = true
就可以正常工作。默认情况下,如果输出设备是TTY,则自动刷新输出,否则进行缓冲。您可以检查STDOUT.tty?
- 当直接写入终端时为true
,当被管道/重定向时为false
。 - Stefan$stdout.sync
似乎默认为true,但是ruby -e 'puts $stdout.sync'
可以显示适用于你的脚本的设置。 - Ry-yes | tail -f
会挂起,尽管man
使用“描述符”作为输入名称。 - Aleksei Matiushkin