Linux uses the concept of “streams” to handle input and output messages. Specifically, there are three:
- stdin: standard input
- stdout: standard output
- stderr: standard error
These streams are defined by the environment in which a command operations, and doesn’t depend on the command itself. So if a script has an output – say via an “echo” statement or it throws an error, these messages will be sent to the appropriate stream.
Often, it’s useful to redirect the error stream to the standard output stream. Let’s see how this happens, and why.
What Happens when Commands Run on Terminals
In a terminal environment, the data streams map to the following locations:
- stdin – maps to the keyboard input
- stdout – maps to the terminal
- stderr – maps to the terminal
The above choices serve to recreate the terminal input as you know it. When a command stops and asks you for input, by default the input is assumed to come from the keyboard. So when you run an install script and it asks you for “Yes (Y) or No (N)”, it means that it’s accepting input from stdin, which in this case is the keyboard. And any messages the program outputs go to the terminal, which is what you see. The same goes for error messages.
No Need to Redirect on the Terminal
If your command runs entirely on the terminal, then you won’t see any difference if you redirect stderr to stdout because they both go to the same location – namely the terminal. But if you want to send the two streams to different destinations, then redirection becomes important.
How to Redirect stderr to stdout
Redirecting the stderr of a command to stdout is simple. Use the following:
command 2>&1
Where “command” refers to any Linux command you want to run. Each data stream corresponds to a number as shown:
- stdin = 0
- stdout = 1
- stderr = 2
So when we want to redirect stderr (2) to stdout (1), we use the above syntax. As you can see, it’s super easy. However, it only lasts for a single command. If you run the above command, the changes won’t persist and for the next command, stderr and stdout will have their separate streams.
If you want the changes to persist for all future commands in the current session, you’ll have to use a command like this:
exec 2>&1
In Linux, when we use the “exec” keyword without a command, the changes apply to the current session. So the above command will redirect stderr to stdout for all future commands. But this will reset once the session changes. If you want to make the change permanent, you can include it in .bashrc and then you won’t have to repeat the command each time you start a shell session.
But this is hardly every necessary. The overwhelming majority of the time, you just want to redirect stderr to stdout on a temporary basis for a single command. As we’ve seen, the context is never to change the output of the default terminal output because they’re both linked to the same destination.
But here is a set of reasons why it can be useful to redirect stderr to stdout in Linux.
Uses of Redirecting stderr to stdout
These are use cases when it’s useful to have the error message and the output go to the same location.
Saving Output to a Log File
There might be situations where you don’t want the command to display its output on the terminal. Either it’s too voluminous to be of use, or maybe it’s a long-running command that works in the background and you don’t want it to constantly interrupt the terminal with output and potential errors while you work. At the same time, you want to preserve this information in case it’s useful later on.
For example, you can use this command to send everything – output and errors – to a single log file:
[command] >full_log.txt 2>&1
For example, consider the following command:
ls /etc/passwd /non_existing_file
The above command attempts to list two files. One of them exists, and the other one doesn’t. As a result, it will generate both a regular output as well as an error as shown here:
Since by default, both outputs and errors go to the terminal, they’re both shown at the same time. But let’s say you wanted to redirect everything to a log file, then the following command would accomplish that:
ls /etc/passwd /non_existing_file >full_log.txt 2>&1
You can see how it works in the screenshot below:
You can see that the command itself doesn’t generate any output on the terminal. That’s because we’ve redirected both the error message and the output to a file called “full_log.txt”. When I print the contents of the file, you can see that it contains both.
So that’s the first use of this kind of redirection – allowing a file to capture the outputs without dumping them to the terminal.
Piping Outputs to Another Command
Linux allows us to use the output of one command as an input to another command. I’d earlier written about using the pipe operator in Linux, and the most common command that accepts the output of other commands is “grep”.
However, by default, the pipe operator only passes through the output of the earlier command, and not the error messages. While this is what you want in many cases, sometimes you want the destination command to process the errors as well. For example. let’s say you have a command that has a long output. But you want to see whether there are any errors hidden in the output. If you just use the following:
ls /etc/passwd /non_existing_file | grep --color=always "cannot"
The above command generates the following error:
ls: cannot access '/non_existing_file': No such file or directory
Unfortunately, even though the error message contains the word “cannot”, grep can’t find it because the pipe doesn’t pass grep the error message.
So what we want is to first redirect stderr to stdout, and then use the pipe operator to grep. This way, grep can search everything. Here’s what the new command looks like:
ls /etc/passwd /non_existing_file 2>&1 | grep --color=always "cannot"
This gives us the following output:
You can see that in the first command, grep doesn’t color the output, while after piping the two together, it finds what we’re looking for. So if you want to use grep to filter long outputs for error messages, then you need to redirect stderr to stdout.
Piping the Output of Cron Jobs
The cron jobs that run in Linux don’t have access to a terminal, so both their regular output and error messages are lost. If you want to access these streams for debugging, you need to combine them and redirect them to a file. Something like this:
* * * * * /path/to/command.sh > /var/log/command.log 2>&1
The above cron job runs “.sh”, combines the error and output streams, and sends them to a log file that you can examine at leisure.
Conclusion
Redirecting stderr to stdout can seem like an edge scenario, but it’s actually a crucial part of a system’s workings, especially when examining the outputs of background processes and cron jobs. It’s even useful for filtering out error messages in a long stream of intermingled output and error. Hopefully, you can see how easy it is to accomplish!
I’m a NameHero team member, and an expert on WordPress and web hosting. I’ve been in this industry since 2008. I’ve also developed apps on Android and have written extensive tutorials on managing Linux servers. You can contact me on my website WP-Tweaks.com!
Leave a Reply