Ruby使用$ stdout来写入puts和return的输出吗?

时间:2014-01-24 22:18:10

标签: ruby irb pry

我想知道Ruby使用的输出流在命令行打印这些东西:

irb(main):001:0> a="test"
=> "test"
irb(main):002:0> puts a
test
=> nil
irb(main):003:0> a
=> "test"

$stdoutirb(main):002:0>使用了irb(main):003:0>吗?并且,这两次调用之间$stdout的值是否有任何变化?

另外,有人能指出我从这些东西打印/写入的Ruby源吗?

2 个答案:

答案 0 :(得分:8)

是。并且很容易测试/证明自己。请在命令行中尝试:

ruby -e 'puts "foo"' > test.out
cat test.out

输出将是:

foo

Ruby使用STDOUT通道输出到控制台。然后操作系统将STDOUT重定向到“test.out”。

尝试使用:

ruby -e 'STDOUT.puts "foo"' > test.out

你会得到相同的结果。

如果我们这样做:

ruby -e 'STDERR.puts "foo"' > test.out
foo
cat test.out

您在文件中看不到任何内容,但“foo”将被写入STDERR频道的控制台。

Ruby将$stdout定义为您可以更改的全局,并将STDOUT定义为常量,您不应更改。同样,$stderrSTDERR可用。

现在,这里变得有趣,并证明了你的问题。试试这个:

ruby -e '$stdout = STDERR; puts "foo"' > test.out

并且您将输出与STDERR时相同的结果,因为puts正在使用$stdout的值来选择输出流,并写入STDERR 。当解释器启动时,Ruby会从操作系统中获取这些流值,并在脚本运行时记住这些值。您可以在必要时更改它们 并且Ruby会在解释器退出时忘记这些设置,并在下次将其自身重置为正常状态。

您不应该依赖于更改$stdout的隐含/不可见行为,因为这会导致真正令人困惑的代码。相反,我强烈建议您在写入STDERR时使用显式STDERR.puts,并使用裸puts来正常输出到STDOUT。如果您将输出混合到两者,那么使用STDOUT.putsSTDERR.puts可能会更清楚,但这是您的通话。

现在,IRB与在解释器中运行的常规脚本相同,只要使用$stdout,因此将IRB中的输出写入$stdout的工作方式相同:

irb(main):001:0> $stdout
#<IO:<STDOUT>>
irb(main):002:0> $stderr
#<IO:<STDERR>>

irb(main):003:0> $stdout.puts 'foo'
foo
nil
irb(main):004:0> $stderr.puts 'foo'
foo
nil

最后:

irb(main):007:0> $stdout.isatty
true
irb(main):008:0> $stdout.isatty
true

在我们看起来稍低之前,我们无法区分任何差异;它们都是TTY通道,标准STDOUT和STDERR通道号:

irb(main):009:0> $stdout.fileno
1
irb(main):010:0> $stderr.fileno
2

希望这有助于'摒弃它。


我刚刚意识到IRB报告puts的返回值可能让您感到困惑,导致您认为STDOUT正在发生变化。返回nil与STDOUT或STDERR无关。这是因为puts返回nil,IRB会尽职尽责地报告。

答案 1 :(得分:1)

发生这种情况的原因是因为IRB会在每次操作后调用对象。

有关详细信息,请参阅Object#inspect:

http://ruby-doc.org/core-2.1.0/Object.html#method-i-inspect

我们可以通过覆盖检查来证明这一点:

 ~ $ irb
>> class Foo
>> def inspect
>> 'hi'
>> end
>> end
=> nil
>> foo = Foo.new
=> hi

在你的情况下唯一能击中$ stdout的是你的puts命令的结果。

希望这有帮助!