我想知道Ruby使用的输出流在命令行打印这些东西:
irb(main):001:0> a="test"
=> "test"
irb(main):002:0> puts a
test
=> nil
irb(main):003:0> a
=> "test"
$stdout
和irb(main):002:0>
使用了irb(main):003:0>
吗?并且,这两次调用之间$stdout
的值是否有任何变化?
另外,有人能指出我从这些东西打印/写入的Ruby源吗?
答案 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
定义为常量,您不应更改。同样,$stderr
和STDERR
可用。
现在,这里变得有趣,并证明了你的问题。试试这个:
ruby -e '$stdout = STDERR; puts "foo"' > test.out
并且您将输出与STDERR
时相同的结果,因为puts
正在使用$stdout
的值来选择输出流,并写入STDERR 。当解释器启动时,Ruby会从操作系统中获取这些流值,并在脚本运行时记住这些值。您可以在必要时更改它们 并且Ruby会在解释器退出时忘记这些设置,并在下次将其自身重置为正常状态。
您不应该依赖于更改$stdout
的隐含/不可见行为,因为这会导致真正令人困惑的代码。相反,我强烈建议您在写入STDERR时使用显式STDERR.puts
,并使用裸puts
来正常输出到STDOUT。如果您将输出混合到两者,那么使用STDOUT.puts
和STDERR.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命令的结果。
希望这有帮助!