I will not write all story here but people were using Teleprinter (Teletypewriter, Teletype, TTY) from 1830s and 1840s. As seen in the following pictures, it was an electromechanical device used for communicating text over telegraph lines etc. There wasn't any monitor, output was written in a paper. Some models were creating punched tape for data storage (either from typed input or from data received from a remote source) and read back such tape for local printing or transmission.
Nowadays, we use computers with monitor and operating system but Linux still uses TTY concept under the hood 🙂
You can find some diagrams below relation with Terminal Emulator and TTY
stdin, stdout and stderr
Linux attaches stdin, stdout and stderr streams for each program by default in the Linux terminal. These streams carry text as data. So, streams are used to pass data into programs and to get data out of them.
Execution Life cycle of one program in Linux
Execution Life cycle of piped two programs in Linux
Execution Life cycle of piped three programs in Linux
In Linux, almost all the streams are treated as if they were files. Just like you can read/write a file, you can read/write a data from these streams.
stdin: Stands for standard input. It takes text as input.
stdout: Stands for standard output. The text output of a command is stored in the stdout stream.
stderr: Stands for standard error. Whenever a command faces an error, the error message is stored in this stream.
Each stream has file descriptor ID as below
- stdin – /dev/stdin or /dev/fd/0
- stdout – /dev/stdout or /dev/fd/1
- stderr – /dev/stderr or /dev/fd/2
Stdin example
read command require input from the keyboard.
When no argument is provided to read command, the entire line is assigned to the REPLY variable. So, we can print REPLY variable in terminal as below.
$ read
Hello World
$ echo $REPLY
Hello World
Stdout example
Output of echo
command is written to terminal or stdout
$ echo "Hello World"
Hello World
Piping Streams
The | sign is responsible for piping the stdout stream of a command to the stdin stream of next command.
The |& sign is responsible for piping both stdout and stderr streams of a command to the stdin stream of next command.
Piping stream is a form of redirection. It only redirect stdin, stdout and stderr streams.
$ echo "Hello World" | grep Hello
Hello World
The output of echo command is written in the stdout stream, then the piping redirects the content of stdout to stdin for the grep command. That's how grep command knows what content to perform the operation on.
If you want to pipe both the stdout and stderr to the next command, then use the I& instead of I
$ anything |& cat
zsh: command not found: anything
Redirecting Streams
The > sign is responsible for redirecting the stdout stream of a command to a file stream.
The >> sign is responsible for appending the stdout stream of a command to a file stream.
The < sign is responsible for redirecting the file stream to a stdin stream of a command.
The << sign is responsible for redirecting the multi-line string to a stdin stream of a command. It is also known as here-document.
The <<< sign is responsible for redirecting the single string to a stdin stream of a command. It is also known as here-string.
The >& sign is responsible for redirecting and merging both stdout and stderr streams of a command to the file stream.
Redirecting stream is similar to Piping stream but it is used for file stream to stdin or stdout streams.
Redirecting stdout stream of a command to file stream
$ echo "Hello World" > hello.txt
or
$ echo "Hello World" 1> hello.txt
Redirecting stderr stream to file stream
$ something 2> error.txt
/dev/null is a special file which ignores anything put into it.
$ something 2> /dev/null
Appending stdout stream of a command to file stream
$ echo "How is the weather today?" >> hello.txt
or
$ echo "How is the weather today?" 1>> hello.txt
Redirecting file stream to stdin stream of a command
$ cat < hello.txt
Hello World
or
$ echo "Hello World" | cat
Hello World
Redirecting file stream to stdin stream of a command as parameter
$ cat > input.txt <<EOL
kenan
kenanhancer@gmail.com
EOL
$ cat > greeting.sh <<EOL
#!/bin/bash
echo "Enter name"
read name
echo "Enter email"
read email
echo "Your name is $name and email is $email"
EOL
$ . ./greeting.sh < input.txt
Enter name
Enter email
Your name is kenan and email is kenanhancer@gmail.com
Redirecting file stream to stdin stream of a command as parameter and redirecting stdout stream of command to file stream.
$ . ./greeting.sh < input.txt > greetingOutput.txt
$ cat greetingOutput.txt
Enter name
Enter email
Your name is kenan and email is kenanhancer@gmail.com
Redirecting stderr and stdout streams to separate file streams
$ echo “hello world” 1> output.txt 2> debug.txt
Some examples
$ ls -l > output.txt
$ wc -l countries.txt > output.txt
$ ls -l >> output.txt
$ wc -l < countries.txt
$ wc -l < countries.txt > output.txt
$ ls -l blabla 2> error.log
$ ls -l blabla >& outputOrError.txt
or
Redirecting stdout stream to file stream and stderr stream to file stream. We redirect to a file stream first then redirect the error stream.
$ ls -l blabla > outputOrError.txt 2>&1
$ ls | head -3 | tail -1 > output.txt
Command Substitution
Command substitution is shown as $() sign.
$ NOW=$(date)
$ echo $NOW
Sun 19 Jun 2022 16:57:16 BST
or
$ echo $(date)
Sun 19 Jun 2022 16:57:16 BST
$ echo "Date is $(date)"
Date is Sun 19 Jun 2022 16:58:02 BST
$ cat <<< "Date is $(date)"
Date is Sun 19 Jun 2022 16:58:02 BST
$ cat <<< $(echo "Date is $(date)")
Date is Sun 19 Jun 2022 16:58:02 BST
$ echo "Date is $(date)" | cat
Date is Sun 19 Jun 2022 16:58:02 BST
Process Substitution
Process substitution is shown as <() sign. Process Substitution writes output in a file and returns that file name.
$ cat <(date)
Sun 19 Jun 2022 16:58:02 BST
$ cat < <(date)
Sun 19 Jun 2022 16:58:02 BST
$ date | cat
Sun 19 Jun 2022 16:58:02 BST
$ echo $(date) | cat
Sun 19 Jun 2022 16:58:02 BST