2014-01-24 82 views
5

我想知道正在使用的紅寶石在命令行來打印這些東西的輸出流:

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

是用於irb(main):002:0>irb(main):003:0>$stdout?而且,這兩個調用之間的$stdout的值是否有任何變化?

另外,有人可以指向我從Ruby源代碼打印/寫入這些東西嗎?

+3

'=> nil'讓你困惑嗎?返回的'nil'與STDOUT或STDERR無關。這是因爲'puts'返回nil,這是由IRB盡職報告的。 –

回答

8

是的。而且很容易測試/向自己證明。嘗試在此命令行:

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

的輸出將是:

foo 

紅寶石使用STDOUT信道,以輸出到控制檯。 OS然後將該STDOUT重定向到「test.out」。

與嘗試:

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

,你會得到同樣的結果。

如果我們這樣做:

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

你會看到什麼文件中,但「富」將被寫入到標準錯誤通道控制檯。

Ruby將$stdout定義爲可以更改的全局,並將STDOUT定義爲常數,您不應該更改該常數。同樣,$stderrSTDERR可用。

現在,這裏是它獲得樂趣,並證明你的問題。試試這個:

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

和,你就會有相同的結果,當我輸出到STDERR,因爲在puts是使用值$stdout選擇輸出流,並寫到STDERR。當解釋器啓動時,這些流值由操作系統從操作系統中拾取,並在腳本的運行時記住。如果需要,您可以更改它們並且Ruby將在解釋器退出時忘記這些設置,並在下次重置爲正常狀態。

儘管如此,您不應該依賴於更改$stdout的隱含/不可見行爲,因爲這會導致代碼混亂。相反,我強烈建議您在寫入STDERR的任何時候使用明確的STDERR.puts,並且正常輸出爲STDOUT時使用puts。如果你將輸出混合到兩者,那麼使用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 

希望幫助「splain它。


我剛剛意識到IRB的的puts返回值的報告可能會混淆你,導致你認爲stdout是不斷變化的。返回nil與STDOUT或STDERR無關。這是因爲puts返回零,這是由IRB盡職報告。

+0

很好的回答!我發現它非常有幫助。 –

1

發生的原因是因爲IRB在每次操作後都會調用對象。

請參見對象#檢查的全部細節:

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命令的結果。

希望這會有所幫助!