gpt4 book ai didi

ruby - 停止接受管道输入但读取缓冲数据

转载 作者:IT王子 更新时间:2023-10-29 00:45:09 27 4
gpt4 key购买 nike

我有一个应用程序,它从 $stdin 读取并对数据进行一些处理。我想放入一个信号处理程序来捕获 SIGINT/SIGTERM 并优雅地关闭(意味着完成数据处理并在完成后退出)。棘手的部分是我希望它停止从 STDIN 读取但能够处理任何缓冲数据。这样一来,另一个应用程序可以启动并通过相同的 STDIN 管道,并在前一个应用程序停止的地方恢复处理。

问题是如果我关闭 STDIN,缓冲的任何内容都会丢失,或者至少无法访问。

基本上我正在尝试这个:

#!/usr/bin/ruby

Signal.trap('INT') do
$stdin.close
end

f = File.open('/tmp/out', 'a')
while (data = $stdin.read(4096)) != "" do
f.write(data)
end

它立即在 $stdin.read 调用中给出了一个 IOError 异常,即使我知道它读取了一些数据(strace 显示了它)。

(我不需要关闭管道,我这样做只是为了打破 while 循环。如果有更优雅的方式来打破循环并获得缓冲数据,我很乐意接受。)


我知道这种方法适用于操作系统级别(管道缓冲区在传递给另一个应用程序时会保留),因为我可以进行以下测试并且不会丢失任何数据:

# source.rb
i = 0
loop do
puts "%08d" % (i += 1)
end

.

# reader.rb
$stdout.write($stdin.read(9))
$stdin.close

.

ruby /tmp/source.rb | while true; do ruby reader.rb; sleep 1; done
00000001
00000002
00000003
00000004
00000005

最佳答案

解决这个问题的一种方法是在关闭原始文件描述符之前复制文件描述符,然后错误将中断循环,您可以从未关闭的重复文件句柄中读取其余数据。

(对不起,如果这段代码不好,我不懂 ruby​​)

#!/usr/bin/ruby

require 'fcntl'

stdin_dup = nil

Signal.trap('INT') do
stdin_dup = File.for_fd($stdout.fcntl(Fcntl::F_DUPFD))
$stdin.close
end

f = File.open('/tmp/out', 'a')
begin
while (data = $stdin.read(4096)) != "" do
f.write(data)
end
rescue IOError
# finish stuff with stdin_dup here
end

关于ruby - 停止接受管道输入但读取缓冲数据,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/17892146/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com