Stdin, Stdout, Stderr explained
Acronyms
| Acronym | Meaning | | ------- | ------------ | | I/O | Input/Output | | std | Standard | | in | Input | | out | Output | | err | Error |
Data streams
Computer processns have diferent data streams.
Data streams are used to communicate with the user and other processs.
There are input data streams and output data streams.
Input data streams
Input data streams are used to get data from the user or other processs:
stdin
Output data streams
Output data streams are used to send data to the user or other processs:
stdout
stderr
Error data streams
Output data streams are also used to send error messages to the user or other processs:
stderr
Shell
$ echo "Hello World"
When we run the above command in the shell, all our data streams are directly connected to the terminal.
This means that the input is read from the keyboard and the output is displayed on the screen.
Redirection
By default, all data streams are connected to the terminal.
This means that the input is read from the keyboard and the output is displayed on the screen.
But these are just the default connections.
We can change the connections between the process and the data streams however we want.
Changing the connections between the process and the data streams is called redirection.
We can redirect all data streams or just some of them.
Output redirection
$ echo "Hello World" > hello.txt
When we run the above command in the shell, the input is still read from the keyboard.
But the terminal is no longer connected to the output data stream of the process.
Instead the output data stream is connected to the file hello.txt
.
The output is no longer displayed on the screen. It is written to the connected file.
Input redirection
$ cat < hello.txt
When we run the above command in the shell, the output is still displayed on the screen.
But the terminal is no longer connected to the input data stream of the process.
Instead the input data stream is connected to the file hello.txt
.
The input is no longer read from the keyboard. It is read from the connected file.
Pipe
$ echo "Hello World" | cat
We can connect the output data stream of one process to the input data stream of another process.
This is called a pipe.
The whole command is called a pipeline.
We can have as many pipes as we want.
Each pipe connects the output data stream of one process to the input data stream of the next process.
File descriptors
File descriptors are used to identify data streams.
| File descriptor | Data stream | | --------------- | ----------- | | 0 | stdin | | 1 | stdout | | 2 | stderr |
Differentiate output streams
When redirecting data streams, we can use the file descriptors to differentiate the output streams.
1
is the file descriptor for the normal output stream.
$ echo "Hello World" 1> hello.txt
The normal output stream is the default ouptut stream.
So we can omit the file descriptor:
$ echo "Hello World" > hello.txt
2
is the file descriptor for the error output stream.
$ echo "Hello World" 2> error.txt
Individual files
Redirect both output streams into individual files in one command:
$ echo "Hello World" 1> hello.txt 2> error.txt
Same file
Redirect both output streams into the same file in one command:
$ echo "Hello World" &> hello.txt
Detecting redirection
processs can detect if their data streams are connected to a terminal.
This can be used to conditionally display output.
For example, we may want to display text differently if the output is redirected to a file and not displayed on the screen.
In bash scripts, we can use the [[ -t FD ]]
condition to detect if a file
descriptor is connected to a terminal.
FD
is the file descriptor.
Detecting input redirection
#!/bin/bash
if [[ -t 0 ]]; then
echo "stdin via terminal"
else
echo "stdin via file or pipe"
fi
The first condition is true when the input stream is comming from the terminal directly:
$ ./script.sh
The second condition is true when the input stream is comming from a file:
$ ./script.sh < hello.txt
Or from a pipe:
$ echo "Hello World" | ./script.sh
Detecting output redirection
#!/bin/bash
if [[ -t 1 ]]; then
echo "stdout via terminal"
else
echo "stdout via file or pipe"
fi
The first condition is true when the output stream is comming from the terminal directly:
$ ./script.sh
The second condition is true when the output stream is going into a file:
$ ./script.sh > hello.txt
Or into a pipe:
$ ./script.sh | cat
Examples from other languages
Node.js
process.stdin.on("data", (data) => {
process.stdout.write(data.toString().toUpperCase())
})
Python
import sys
for line in sys.stdin:
sys.stdout.write(line.upper())
PHP
<?php
while ($line = fgets(STDIN)) {
fwrite(STDOUT, strtoupper($line));
}