Ruby 红宝石破裂的管道@io_write-<;标准件>;

Ruby 红宝石破裂的管道@io_write-<;标准件>;,ruby,pipe,stdout,Ruby,Pipe,Stdout,在尝试运行ruby程序并将输出传送到另一个程序时,如下所示: ruby hello.rb | whoami a | b 命令whoami按预期首先执行,但之后,hello.rb会崩溃: Traceback (most recent call last): 2: from p.rb:2:in `<main>' 1: from p.rb:2:in `print' p.rb:2:in `write': Broken pipe @ io_write - <STDOU

在尝试运行ruby程序并将输出传送到另一个程序时,如下所示:

ruby hello.rb | whoami
a | b
命令
whoami
按预期首先执行,但之后,hello.rb会崩溃:

Traceback (most recent call last):
    2: from p.rb:2:in `<main>'
    1: from p.rb:2:in `print'
p.rb:2:in `write': Broken pipe @ io_write - <STDOUT> (Errno::EPIPE)
[当管道传输到另一个程序时,
STDOUT.put
之后的
STDOUT.flush
会引发类似的错误]

这次事故的原因是什么?

导言 首先,可以找到一个解释

不管怎样,这是我的想法

当管道按如下方式使用时:

ruby hello.rb | whoami
a | b
a和b都被执行。b等待a的标准输入

说到Errno::EPIPE,他们说:

EPIPE fd连接到读取端为的管道或插座 关闭当这种情况发生时,书写过程也会发生 接收信号管信号。(因此,写入返回值为 仅当程序捕获、阻止或忽略此项时才可见 信号。)

谈论问题中的问题: 当程序
whoami
运行时,它退出并不再接受ruby程序
hello.rb
正在发送的标准输入-导致管道破裂

在这里,我编写了两个ruby程序,分别命名为p.rb和q.rb来测试:

bash[~] $ ruby p.rb | ruby q.rb

Traceback (most recent call last):
    2: from p.rb:2:in `<main>'
    1: from p.rb:2:in `print'
p.rb:2:in `write': Broken pipe @ io_write - <STDOUT> (Errno::EPIPE)

bash[~] $ ruby p.rb | ruby q.rb
bash[~] $ time ruby p.rb | q.rb
Traceback (most recent call last):
    2: from p.rb:2:in `<main>'
    1: from p.rb:2:in `print'
p.rb:2:in `write': Broken pipe @ io_write - <STDOUT> (Errno::EPIPE)

real    0m3.186s
user    0m0.282s
sys 0m0.083s
  • p、 铷
  • q、 铷
跑步:

bash[~] $ ruby p.rb | ruby q.rb

Traceback (most recent call last):
    2: from p.rb:2:in `<main>'
    1: from p.rb:2:in `print'
p.rb:2:in `write': Broken pipe @ io_write - <STDOUT> (Errno::EPIPE)

bash[~] $ ruby p.rb | ruby q.rb
bash[~] $ time ruby p.rb | q.rb
Traceback (most recent call last):
    2: from p.rb:2:in `<main>'
    1: from p.rb:2:in `print'
p.rb:2:in `write': Broken pipe @ io_write - <STDOUT> (Errno::EPIPE)

real    0m3.186s
user    0m0.282s
sys 0m0.083s
跑步:

bash[~] $ ruby p.rb | ruby q.rb

Traceback (most recent call last):
    2: from p.rb:2:in `<main>'
    1: from p.rb:2:in `print'
p.rb:2:in `write': Broken pipe @ io_write - <STDOUT> (Errno::EPIPE)

bash[~] $ ruby p.rb | ruby q.rb
bash[~] $ time ruby p.rb | q.rb
Traceback (most recent call last):
    2: from p.rb:2:in `<main>'
    1: from p.rb:2:in `print'
p.rb:2:in `write': Broken pipe @ io_write - <STDOUT> (Errno::EPIPE)

real    0m3.186s
user    0m0.282s
sys 0m0.083s
对,它实际上什么也没显示。原因是q.rb现在等待标准输入显然,等待是这里最重要的。现在,p.rb即使使用
STDOUT.sync
STDOUT.flush
管道传输到此q.rb,也不会崩溃

另一个例子:
  • p、 铷
跑步:

bash[~] $ ruby p.rb | ruby q.rb

Traceback (most recent call last):
    2: from p.rb:2:in `<main>'
    1: from p.rb:2:in `print'
p.rb:2:in `write': Broken pipe @ io_write - <STDOUT> (Errno::EPIPE)

bash[~] $ ruby p.rb | ruby q.rb
bash[~] $ time ruby p.rb | q.rb
Traceback (most recent call last):
    2: from p.rb:2:in `<main>'
    1: from p.rb:2:in `print'
p.rb:2:in `write': Broken pipe @ io_write - <STDOUT> (Errno::EPIPE)

real    0m3.186s
user    0m0.282s
sys 0m0.083s
  • q、 铬
我编译了它们,然后运行:

bash[~] $ time ./p | ./q

real    0m3.013s
user    0m0.007s
sys 0m0.019s
二进制文件./p在将近3秒钟内处理
未处理的异常:写入文件时出错:管道破裂(Errno)
并退出。同样,两个crystal程序可能需要0.01秒来执行,内核也可能需要一些时间来运行进程

还要注意的是,
STDERR#print
STDERR#put
STDERR#putc
STDERR#printf
STDERR#write
STDERR#syswrite
即使输出同步,也不会引发Errno::epie

结论 管道是。将
STDOUT#sync
设置为true或使用
STDOUT#flush
将所有缓冲数据刷新到基础操作系统

运行
hello.rb | whoami
时,如果不同步,我可以写入8191字节的数据,并且程序hello.rb不会崩溃。但是使用sync,通过管道写入1字节将导致hello.rb崩溃


因此,当hello.rb与管道程序
whoami
同步标准输出时,
whoami
不会等待hello.rb;hello.rb引发了
Errno::eppe
,因为这两个程序之间的管道断开了(如果我在这里迷路了,请纠正我)。

问题在于
whoami
正在写入STDOUT,而通过刷新缓冲区,您的ruby脚本现在正在写入断开的管道。关于这个问题,这里有一篇很好的文章: