stdin stdout and stderr in Linux and Unix (macOS)

Friday, July 12, 2024 at 10:19 AM | 6 min read

Last modified on Saturday, July 25, 2026 at 12:36 PM

, , , , ,

A woman with digital code projections on her face, representing technology and future concepts.

Photo by ThisIsEngineering on pexels.com

Table of Contents

I just published a post entitled Redirect operators in Linux and Unix (macOS), in which I discussed how to redirect stdin (standard input) and stdout (standard output), and why one would want to do it in the first place. This post will take the concept of redirection to the next level.

In Redirect operators in Linux and Unix (macOS), I discussed default stdin and stdout and their associated redirect operators: < representing the stdin redirect operator, and > representing the stdout redirect operator. There is a third data stream called stderr.

The stdin, stdout, and stderr data streams in Linux

There are three data streams in Linux that can be used to transport data related to a command. As discussed in my article entitled Redirect operators in Linux and Unix (macOS), stdin is the input stream, stdout is the output stream, and then there is stderr, which is the error stream. If you are a developer, IT network administrator, network support specialist, or cybersecurity professional, for example, you are very familiar with errors. Cybersecurity professionals are constantly dealing with logging errors related to network security.

stdin, stdout, and stderr are three standard data streams that one creates when executing a command in Linux. And what is a stream? According to opensource.com,

As its name implies, a data stream is a stream of data—especially text data—being passed from one file, device, or program to another using STDIO (stdin/stdout). — David Both, opensource.com

And then David Both goes on to say,

In the Unix and Linux worlds, a stream is a flow of text data that originates at some source; the stream may flow to one or more programs that transform it in some way, and then it may be stored in a file or displayed in a terminal session. As a sysadmin, your job is intimately associated with manipulating the creation and flow of these data streams. In this post, we will explore data streams—what they are, how to create them, and a little bit about how to use them.

stdin is represented by File descriptor 0, stdout is represented by File descriptor 1, and stderr is represented by File descriptor 2.

Streams are treated like files in Linux

So why File descriptor 0, File descriptor 1, and File descriptor 2, when dealing with stdin, stdout, and stderr? Because in Linux, streams are treated like files. We can read a file or write data into a file.

stderr data stream

When a stdout is redirected to a file instead of Terminal, the stdout is not displayed in the Terminal window because of an error in the data output represented by stderr. There is a redirect operator that can redirect the stderr data from Terminal to another source. This can also ensure that the data persists and is saved somewhere (else). This proves very useful in cybersecurity for saving network logging errors to a file, for example.

Let's say I run a command in Terminal that lists the contents of a directory that does not exist:

ls linux-scripting

The command produces:

ls: cannot access 'linux-scripting': No such file or directory

Let's say I run ls linux-scripting but redirect the command:

ls linux-scripting > list-directory.txt

It adds the following to the list-directory.txt file:

ls: cannot access 'linux-scripting': No such file or directory

The same message is output to Terminal, because stderr itself has not been redirected. Now let's say I run:

ls linux-scripting 2> list-directory.txt

The following is returned:

That's right. Nothing! That's because I am using a stderr redirect operator. The 2 points to stderr (represented by File descriptor 2), and > is the stdout redirect operator, and redirects the stderr output to the list-directory.txt file. When I open list-directory.txt with the vim command:

vim list-directory.txt

or run the cat command on list-directory.txt:

cat list-directory.txt

the command outputs the following in Vim or Terminal:

ls: cannot access 'linux-scripting': No such file or directory

I can also redirect both stdout and stderr to my list-directory.txt file:

ls macos-scripting linux-scripting > list-directory.txt 2>&1

It produces:

ls: cannot access 'linux-scripting': No such file or directory macos-scripting:

Now two lines exist. macos-scripting: just means that it is an empty directory (which it actually is). And what does 2>&1 mean? It means that I want to redirect the output of both my stdout represented by File descriptor 1 and stderr represented by File descriptor 2 to my list-directory.txt file. The regular stdout redirect operator redirects the output of ls macos-scripting linux-scripting to list-directory.txt. But since there is no linux-scripting directory, the stderr resulting from that redirects to list-directory.txt as well, but does not output to Terminal because of the 2>&1 stderr stdout redirect.

There is also a shortcut for 2>&1. It is:

ls macos-scripting linux-scripting &> list-directory.txt

The result is the same as for 2>&1 appended to the end of the command.

When I run vim list-directory.txt, it yields:

ls: cannot access 'linux-scripting': No such file or directory macos-scripting:

When I run cat list-directory.txt, it also responds with:

ls: cannot access 'linux-scripting': No such file or directory macos-scripting:

Suppressing output with /dev/null

But let's say that I want to get rid of the stderr message altogether? I could run:

ls linux-scripting macos-scripting 2> /dev/null > list-directory.txt

Then I run cat list-directory.txt, which returns:

macos-scripting: script1.txt script2.txt

This time the macos-scripting directory is not empty. It contains two files called script1.txt and script2.txt. There is no error message because it was redirected to a special file called /dev/null on the Linux OS.

According to Aidela Karamyan on baeldung.com,

In the shell scripting world /dev/null is a fundamental concept. Its accidental deletion might wreak havoc on the system because many system processes rely on it. So, knowing what /dev/null is and how to work with it is essential for any Linux developer. — Aidela Karamyan, baeldung.com

She goes on to say,

In Linux systems, devices are files stored in the /dev directory. These files can represent both physical and virtual devices. /dev/null is a virtual null device used to discard any output redirected to it. — Aidela Karamyan, baeldung.com

I can also suppress stdout. Perhaps in certain cases all I want to save is the stderr message and not the stdout data. Let's try that out!

ls macos-scripting linux-scripting &> /dev/null

returns nothing. ls macos-scripting is also suppressed. But when I run the following:

ls macos-scripting

it returns:

script1.txt script2.txt

ls macos-scripting linux-scripting &> /dev/null suppresses both stdout and stderr, redirecting their outputs to the special /dev/null file which then discards that redirected output forever.

If I run:

ls macos-scripting > /dev/null

it is the same as running the command ls macos-scripting 1> /dev/null. By omitting the File descriptor, 1 or 2, it implicitly refers to stdout, because > is the stdout redirect operator and it has a File descriptor of 1.

Now let's say I ran:

echo Hi there! > /dev/null

And then ran:

cat /dev/null

It would produce:

That's right. Nothing. /dev/null discards Hi there!.

macOS vs. Linux: MULTIOS and double redirects

But let's say I did the following:

ls macos-scripting linux-scripting &> list-directory1.txt > list-directory2.txt

And then I ran:

cat list-directory1.txt

It would result in:

# list-directory1.txt ls: linux-scripting: No such file or directory macos-scripting: -file ... (truncated)

And:

cat list-directory2.txt

Would yield:

# list-directory2.txt macos-scripting: -file ... (truncated)

Since I run ls macos-scripting linux-scripting &> list-directory1.txt > list-directory2.txt on macOS, the output of the command exhibited macOS MULTIOS behavior. What does that mean? It means that it duplicates the output to both the first and second redirect destinations.

Just like the example in Redirect operators in Linux and Unix (macOS), MULTIOS merges the output of ls linux-scripting with ls macos-scripting in list-directory1.txt and only the output of ls macos-scripting is redirected to list-directory2.txt. As expected with &>, the output of stderr is included in list-directory1.txt along with the output of ls macos-scripting. So MULTIOS repeats the ls macos-scripting output to both list-directory1.txt and list-directory2.txt.

If I were to run the following in Linux Mint:

ls cron-job-scripts linux-scripting &> file-one.txt > file-two.txt

And then I ran

cat file-one.txt

It would return the following in Terminal:

ls: cannot access 'linux-scripting': No such file or directory

And if I ran:

vim file-one.txt

It would yield the same content:

ls: cannot access 'linux-scripting': No such file or directory

If I ran:

cat file-two.txt

It would produce the following in Terminal:

cron-job-scripts: delete_backups.sh desktop_backup.sh home.txt

And if I ran:

vim file-two.txt

It would also yield:

# file-two.txt cron-job-scripts: delete_backups.sh desktop_backup.sh home.txt

Linux bash does not have the MULTIOS feature. So when I ran ls cron-job-scripts linux-scripting &> file-one.txt > file-two.txt, it only output ls: cannot access 'linux-scripting': No such file or directory in file-one.txt and only listed the contents of cron-job-scripts in file-two.txt. The stderr message and the contents of cron-job-scripts aren't merged together as expected in file-one.txt because, as I state in Redirect operators in Linux and Unix (macOS):

So in macOS zsh, MULTIOS merges &> + redirect into one integrated stream by default. In Linux bash, the redirect overrides &>, so ls's output is ignored.

In this case, it is not that ls's output is entirely ignored. It's only ignored as far as file-one.txt is concerned. It still lands in file-two.txt. So it never reaches file-one.txt, though it's still captured in file-two.txt.

stdin vs stdout vs stderr

Stream nameAbbreviationFile descriptor no.Default destinationRedirect operator
standard inputstdinFile descriptor 0Keyboardinput redirect operator (<)
standard outputstdoutFile descriptor 1Terminaloutput redirect operator (>)
standard errorstderrFile descriptor 2Terminalstderr redirect operator (2>)
standard output + standard errorstdout + stderrFile descriptor 1 + File descriptor 2Terminalstderr to stdout redirect (2>&1)
standard output + standard errorstdout + stderrFile descriptor 1 + File descriptor 2Terminalstderr + stdout redirect to the same destination (&>)

Conclusion

This article continues where Redirect operators in Linux and Unix (macOS) left off. I round off stdin and stdout by introducing stderr. stderr is critical to roles in Information Technology, cybersecurity, and software application development. What differentiates the stderr stream from stdin and stdout is that stderr is specifically used for error messages, while stdin is the input stream for data, and stdout is the output stream for normal results or informational messages. This separation helps distinguish regular output from error messages, making it easier to debug programs.