【问题标题】:Writing to /dev/stdout as a file fails with Errno::EACCES when stdout is redirected重定向标准输出时,将 /dev/stdout 作为文件写入失败并出现 Errno::EACCES
【发布时间】: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 中是可能的,但在重定向时却不是?

【问题讨论】:

    标签: ruby io stdout


    【解决方案1】:

    我认为答案在 Ruby IO::new documentation

    原IO的打开方式为只读时,不能改成可写方式。同样,打开模式不能从只写变为可读。 尝试进行此类更改时,会根据平台在不同位置引发错误。

    w打开IO对象意味着:

    "w" 只写,截断现有文件 长度为零或创建一个新文件进行写入。

    w+打开IO对象意味着:

    "w+" 读写,将现有文件截断为零长度 或者创建一个新的文件进行读写。

    问题似乎是您无法使用w+ 打开stdout,因为权限是针对write only。 问题是为什么只有在使用输出重定向时才会引发错误。

    答案可能在我引用的上一条语句中:

    尝试进行此类更改时,会根据平台在不同位置引发错误。

    我建议在 Standard Library 中使用 StringIO 的对象,而不是 /dev/stdout 进行“实验”。

    评论后添加

    我现在意识到你需要传递一个字符串。

    在这种情况下,我会尝试'/dev/tty',我认为它可以工作,因为它还没有被写入权限打开。

    问题是你应该使用正确的tty 而不是GUI 内的模拟终端来查看结果,或者你应该找到一种方法将tty 输出通过管道传输到另一个IO。仅对Unix 更重要,例如OS

    【讨论】:

    • 相信我,如果 API 采用 IO 对象,我会使用 StringIO。我可能别无选择,只能对调用 File.open() 的方法进行修补。
    • @David Moles 好的,我现在意识到您需要以某种方式传递一个字符串,我根据您的评论更新了我的答案。
    猜你喜欢
    • 2013-10-09
    • 1970-01-01
    • 2012-08-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-04-05
    • 2015-12-03
    相关资源
    最近更新 更多