【发布时间】:2020-07-31 21:22:23
【问题描述】:
我有一个我正在使用的遗留 gem,给定一个文件名,知道如何写入文件,但不知道如何写入 stdout 或任何其他形式的 IO。为了使它更灵活,我试图通过传递/dev/stdout 作为文件名来欺骗它写入标准输出。如果我在终端中运行调用 gem 的代码,并且不重定向输出,则此方法有效。但是,如果我尝试将输出重定向到不同的文件或设备,则会失败并显示Permission denied @ rb_sysopen - /dev/stdout (Errno::EACCES)。
在对 gem 的源代码进行了一些实验和挖掘之后,我想出了以下方法来重现该问题。鉴于此 Ruby 脚本stdout.rb:
#!/usr/bin/env ruby
File.open('/dev/stdout', 'w+') do |f|
f.puts('Hello, world')
end
(在此示例中,我打开文件 w+,因为这是旧版 gem 所做的,但它与 a+ 以同样的方式失败。)
我可以在终端中运行脚本,并且可以运行:
$ ./stdout.rb
Hello, world
但是,如果我将其重定向到一个文件,将其通过管道传输到另一个命令(例如grep),或者尝试使用echo $(./stdout.rb) 之类的内容捕获输出,则会失败:
$ ./stdout.rb > /tmp/hello.txt
Traceback (most recent call last):
2: from ./stdout.rb:3:in `<main>'
1: from ./stdout.rb:3:in `open'
./stdout.rb:3:in `initialize': Permission denied @ rb_sysopen - /dev/stdout (Errno::EACCES)
File.open() 调用似乎失败了。但是,/dev/stdout 在重定向/捕获情况下的权限与仅写入终端时有何不同?
(FWIW,这是在 macOS Catalina 10.15.5、Darwin 19.5.0 上。)
更新:如果我将模式从 w+ 更改为 w,它可以工作。我从IEEE spec 了解到“+”表示“更新”,即阅读和写作。我不清楚为什么遗留 gem 认为它需要它,但更重要的是,为什么这在 TTY 中是可能的,但在重定向时却不是?
【问题讨论】: