How is STDERR.puts different from puts in Ruby?

I'm learning the language from Programming Ruby 1.9, and they toss STDERR.puts into a block of code early in the book without explaining why they're using it or how it's different from puts.

I've googled and wikied the term, but all I can gather from my research is that it's involved in diagnostics. Nowhere in the code provided by Programming Ruby does there seem to be a link to error exception handling.

Here's the code.

require_relative 'csv_reader'
reader = CsvReader.new
ARGV.each do |csv_file_name|
  STDERR.puts "Processing #{csv_file_name}"
  reader.read_in_csv_data(csv_file_name)
end

I did manage to read somewhere that STDERR.puts is used for error handling out of convention, but I guess I'm asking if it acts any differently than puts.


By default, puts writes to STDOUT. By specifying STDERR.puts, you're sending your output to the STDERR handle. Although the implementation behavior is the same, using STDERR instead of STDOUT will definitely impact consumers of your program, since they will be attempting to capture output from your program from STDOUT, by convention. Best practice is to log debugging information, errors, warnings, status, etc to STDERR and actual program output to STDOUT.


Within a *nix based system when a new process is started it will by default have three open filehandles these are as follows

0 - STDIN
1 - STDOUT
2 - STDERR

These numbers, lets call them file descriptors are important to the unix shell that you are using to start your program. STDIN is where your program expects to get its input from (Usually the keyboard unless you've changed that). STDOUT is where your program will write its output (Usually the screen unless you've changed it) and STDERR is where it will write its errors (Again usually the screen unless you've changed it).

The common statement from above is "Unless you've changed it". If you run a command like this

command > file.out

Then the output (everything written to STDOUT) will not show up on screen it will appear in file.out. If you run your command like this

command 2> file.err

Then your output will appear on screen again but any errors written to STDERR will appear in file.err. In fact command > file.out is really shorthand for command 1>file.out. Whatever applies to the > symbol (Redirection) also applies to the | symbol for piping. This means that if you run your program as a filter, receiving data on STDIN and writing to STDOUT then other programs can receive their data from your program but they won't receive the data written to STDERR. (Unless you've asked it to)

You can use both of these commands together like this.

command 1> file.out 2> file.err  # Generally you would leave out the 1

In this instance, not surprisingly the output and error will be in 2 separate files. Bash also has the notion of duplicating file descriptors. This is done with >& operator. The following command will put both STDOUT and STDERR in the same file.

command > file.out 2>&1

What this command is saying is run the command setting up STDOUT to be redirected to file.out then duplicate ( >& ) file descriptor 2 (STDERR) to go to wherever file descriptor 1 is going to (file.out)

You need to be a little careful here with the order that you use these arguments in. Compare the above with this command.

command 2>&1 > file.out

This has an entirely different result. This command says run the command and duplicate STDERR on to STDOUT (At this point in time the terminal) then redirect STDOUT to file.out. Your error text will remain on the screen.


Each program starts with three standard file descriptors when they're spawned: standard input, output and error streams.

The standard input stream is a generic stream from which program input should be read. Likewise, the standard output stream is a generic stream to which program output may be written. So, what is standard error?

The difference between standard output and standard error is subtle but extremely important in UNIX systems due to how programs are used together via pipes. Programs are often designed to consume the output of other programs as their input; this is done by redirecting the standard output of one program to the standard input of another, often via the pipe operator (|). This leaves standard error still connected to the terminal. The user can choose to view the data sent to that stream in the terminal itself, or redirect it to a log file, or to /dev/null, anything the user desires. Note that the data sent to stderr needs not necessarily be error messages; it's just data that is separate from the actual output of the program.

Supporting this paradigm is extremely important for the usability of programs, as it provides a predictable user interface towards program input, output and messages. The user can manipulate these as they see fit, and often interesting applications arise in an unforeseen manner.

So, generally speaking, standard output is for the actual output and standard error is for communicating with the user.