简体   繁体   English

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

[英]Does Ruby use $stdout for writing the output of puts and return?

I want to know the output stream being used by Ruby to print these things at the command-line: 我想知道Ruby使用的输出流在命令行打印这些东西:

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

Is $stdout used for irb(main):002:0> and irb(main):003:0> ? $stdout用于irb(main):002:0>irb(main):003:0> And, is there any change in the value of $stdout between those two invocations? 并且,这两次调用之间$stdout的值是否有任何变化?

Also, can some one point me to the Ruby source from where these things get printed/written? 还有,有人可以指出我从这些东西打印/写入的Ruby源代码?

Yes. 是。 And it's easy to test/prove to yourself. 并且很容易测试/证明自己。 Try this at the command-line: 在命令行尝试此操作:

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

The output will be: 输出将是:

foo

Ruby uses the STDOUT channel to output to the console. Ruby使用STDOUT通道输出到控制台。 The OS then redirects that STDOUT to "test.out". 操作系统然后将该STDOUT重定向到“test.out”。

Try it with: 尝试使用:

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

and you'll get the same result. 你会得到相同的结果。

If we do: 如果我们这样做:

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

You'll see nothing in the file, but "foo" will have been written to the console on the STDERR channel. 您将在文件中看不到任何内容,但“foo”将被写入STDERR频道的控制台。

Ruby defines $stdout as a global you can change, and STDOUT as a constant, which you shouldn't change. Ruby将$stdout定义$stdout可以更改的全局,将STDOUT定义为常量,不应更改。 Similarly, $stderr and STDERR are available. 同样, $stderrSTDERR可用。

Now, here's where it gets fun, and proves your question. 现在,这里变得有趣,并证明你的问题。 Try this: 试试这个:

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

and you'll have the same results as when I output to STDERR , because, at puts was using the value for $stdout to select the output stream, and wrote to STDERR. 并且你将得到与输出到STDERR时相同的结果,因为,在puts中使用$stdout的值来选择输出流,并写入STDERR。 Those stream values are picked up by Ruby from the OS when the interpreter starts, and are remembered during the run-time of the script. 当解释器启动时,Ruby会从操作系统中获取这些流值,并在脚本运行时记住这些值。 You can change them if necessary and Ruby will forget those settings when the interpreter exits, and reset itself to its normal state the next time. 如果需要 ,您可以更改它们,Ruby将在解释器退出时忘记这些设置,并在下次将其自身重置为正常状态。

You shouldn't rely on the implied/invisible behavior of changing $stdout though, because that leads to REALLY confusing code. 您不应该依赖于更改$stdout的隐含/不可见行为,因为这会导致真正令人困惑的代码。 Instead, I'd strongly recommend using an explicit STDERR.puts any time you're writing to STDERR and a bare puts for normal output to STDOUT. 相反,我强烈建议您在写入STDERR时使用显式STDERR.putsputs正常输出用于STDOUT。 If you're intermingling output to both, then it'd probably be clearer to use STDOUT.puts and STDERR.puts , but that's your call. 如果你将输出混合到两者,那么使用STDOUT.putsSTDERR.puts可能会更清楚,但那是你的调用。

Now, IRB is the same as a regular script running in the interpreter is, as far as using $stdout so writing output in IRB to $stdout works the same: 现在,IRB与在解释器中运行的常规脚本相同,就使用$stdout ,在IRB中将$stdout写入$stdout工作方式相同:

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

And: 和:

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

And finally: 最后:

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

We can't really tell any difference until we look a little lower; 在我们看起来稍低之前,我们无法区分任何差异; They're both TTY channels, with the standard STDOUT and STDERR channel numbers: 它们都是TTY频道,标准的STDOUT和STDERR频道号码:

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

Hopefully that helps 'splain it. 希望这有助于'摒弃它。


I just realized that IRB's reporting of the return value of puts might be confusing you, causing you to think that the STDOUT is changing. 我刚刚意识到IRB报告puts的回报值可能让您感到困惑,导致您认为STDOUT正在发生变化。 That nil is returned has nothing to do with STDOUT or STDERR. 返回的nil与STDOUT或STDERR无关。 It's because puts returns nil, which is dutifully reported by IRB. 这是因为puts回报为零,这是由IRB尽职尽责地报道的。

The reason that happens is because IRB calls inspect on the object after each operation. 发生这种情况的原因是因为IRB在每次操作后调用对象。

See Object#inspect for full details: 有关详细信息,请参阅Object#inspect:

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

We can prove this by overriding inspect like so: 我们可以通过覆盖检查来证明这一点:

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

The only thing in your case that's hitting $stdout is the results of your puts command. 在你的情况下唯一触及$ stdout的是你的puts命令的结果。

Hope this helps! 希望这可以帮助!

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM