104

In Ruby, what is the difference between $stdout (preceded by a dollar sign) and STDOUT (in all caps)? When doing output redirection, which should be used and why? The same goes for $stderr and STDERR.

Edit: Just found a related question.

codeforester
  • 39,467
  • 16
  • 112
  • 140
jrdioko
  • 32,230
  • 28
  • 81
  • 120
  • possible duplicate of [What is the difference between STDIN and $stdin in Ruby?](http://stackoverflow.com/questions/4279604/what-is-the-difference-between-stdin-and-stdin-in-ruby) – the Tin Man Jul 13 '11 at 03:23
  • @theTinMan Somewhat it's a duplicate. However it must be noted that whereas the differences between `$stdout` and `STDOUT` vs `$stdin` and `STDIN` are symetrical, the differences between `$stdout` and `$>` vs `$stdin` and `$<` are not. – skalee Mar 03 '16 at 16:59

3 Answers3

120

$stdout is a global variable that represents the current standard output. STDOUT is a constant representing standard output and is typically the default value of $stdout.

With STDOUT being a constant, you shouldn't re-define it, however, you can re-define $stdout without errors/warnings (re-defining STDOUT will raise a warning). for example, you can do:

$stdout = STDERR

Same goes for $stderr and STDERR


So, to answer the other part of your question, use the global variables to redirect output, not the constants. Just be careful to change it back further on in your code, re-defining global variables can impact other parts of your application.

the Tin Man
  • 158,662
  • 42
  • 215
  • 303
Brian
  • 6,820
  • 3
  • 29
  • 27
  • 3
    Actually, if you want to redirect output, you should probably use `$>`, the default output stream, not `$stdout`. – Jörg W Mittag Jul 12 '11 at 22:21
  • 10
    Just found a [comment on another question](http://stackoverflow.com/questions/4279604/what-is-the-difference-between-stdin-and-stdin-in-ruby/4279689#4279689) that says `$stdout` and `$>` are aliases, so reassigning one will affect the other. – jrdioko Jul 12 '11 at 22:47
  • 9
    @jrdioko: You're right. Apparently, I not only learn something new every day, I also forget something every day :-) – Jörg W Mittag Jul 13 '11 at 09:36
  • 2
    And reading more, it sounds like it's better to use [IO#reopen](http://www.ruby-doc.org/core/classes/IO.html#M000890) instead of simple assignment. – jrdioko Jul 13 '11 at 18:53
  • @jrdioko Why do you think it's better to use `IO#reopen` in case of `$stdout`? I totally disagree with this opinion. The `$stdout.reopen` method *mutates* its receiver and that will also affect `STDOUT` if you haven't reassigned `$stdout` before. They aren't meant to be synonyms, it's nothing bad when they hold different values due to assignment, and by reopening the `STDOUT` you're breaking it's purpose. – skalee Mar 03 '16 at 16:43
11

Both $stdout and STDOUT have different meanings. Ruby's documentation is pretty clear on this topic:

  • $stdout – The current standard output.
  • STDOUT – The standard output. The default value for $stdout.

When you want to write to the standard output, then you actually mean the current standard output, thus you should write to $stdout.

STDOUT isn't useless too. It stores the default value for $stdout. If you ever reassign $stdout, then you can restore it to the previous value with $stdout = STDOUT.

Furthermore, there's one more predefined variable:

  • $> – The default output for print, printf, which is $stdout by default.

However it looks like in Ruby 2.3 it simply behaves as an alias for $stdout. Reassigning $stdout changes the value of $> and vice versa.

the Tin Man
  • 158,662
  • 42
  • 215
  • 303
skalee
  • 12,331
  • 6
  • 55
  • 57
6
  • STDOUT is a global constant, so it should not be changed.
  • $stdout is a predefined variable, so it can be changed.

If you are using the shell to do redirection:

$ ruby test.rb > test.log

then it doesn't matter which one you use as the file descriptor for your script is being determined before your script is executed.

However, if you are trying to change the file descriptor for the OS's STDOUT from within your Ruby script, for example to send output to a rotating set of log files based on the current day of the week, then you'll want to make sure you use $stdout.

the Tin Man
  • 158,662
  • 42
  • 215
  • 303
shakerlxxv
  • 412
  • 4
  • 8
  • 5
    "STDOUT is a global constant, so its not going to change". It is a constant, which CAN be changed, but a warning will be issued. `STDOUT = $stderr (irb):1: warning: al#=> #>constant STDOUT >> STDOUT #=> #>` – the Tin Man Jul 13 '11 at 03:25
  • Ahh yes, so should say "so it should not be changed". Thanks! – shakerlxxv Jul 13 '11 at 14:58