In the Linux shell, each process has three file handles (also called file descriptors, or fd's for short) associated with it.
Standard input, or stdin -- numbered as file descriptor "0". This is where the process receives its input from; this is usually the keyboard.
Standard output, or stdout -- numbered as file descriptor "1". This is where the process sends its output to; this is usually the console or terminal screen.
Standard error, or stderr -- numbered as file descriptor "2". This is where the process sends its error messages; this is also usually the console or terminal screen.
You can tell the Linux shell to change any or all of these on a per-command basis, by using pipes ("|") and redirections ("<" and ">").
These features are useful if you want, for example to get the output of a command into a file for later perusal, or if you want to string multiple commands together in order to achieve the desired result.
Remember, Linux is made up of lots of small building blocks that can be put together in order to make something more complicated; the pipes and redirections are what you can use to help join the blocks together.
The standard input is usually taken from what you type in at the keyboard. However we could take the output from a file.
We would use the less than sign (<) to redirect input.
command 0< filename or command < filename |
If we want to store the output of a command in a file we would use standard output and redirect it. Normally by default the output goes to the screen. . If the file doesn't already exist, it will be created.
We use the greater than sign (>) to redirect standard output.
command 1> filename or command > filename |
It is important to think of output from a command and errors produced by a command as separate actions. We might want to store the output of a command in a file and leave the errors to display on the screen. Or we might want to store the error messages in a file.
command 2> filename |
In this instance the number "2" preceding the redirection sign is not optional.
student@debian:~$ touch file1 file2 |
Make sure that file1 and file2 exist in your directory, file3 should not exist.
student@debian:~$ ls file1 file2 file1 file2 |
Standard output goes to the screen and there are no error messages.
student@debian:~$ ls file1 file2 file 3 file3 ls: file3: No such file or directory file1 file2 |
File3 does not exist so a message is printed to standard error. The directory listing for file1 and file2 is printed to standard output.
student@debian:~$ ls file1 file2 file3 > stdout.txt ls: file3: No such file or directory |
Redirect standard output to a file called stdout.txt, standard error is kept as the default display to the screen.
student@debian:~$ ls file1 file2 file3 2> stderr.txt file1 file2 |
Redirect standard error to a file called stderr.txt, standard output is left to the default setting of the screen.
student@debian:~$ ls file1 file2 file3 > stdout.txt 2> stderr.txt student@debian:~$ _ |
Redirect standard output and standard error and nothing is displayed on the screen.
student@debian:~$ cat stdout.txt file1 file2 student@debian:~$ cat stderr.txt ls: file3: No such file or directory |
Check what is in each relevant file.
For standard input we can demonstrate how it works however at this stage of your course it is harder to describe a really useful example.
A simple example would be:
student@debian:~$ cat < stdout.txt file1 file2 |
When we know a little more we could do something more sophisticated, like run a program that normally requires input from a user at a keyboard - but run it after hours in the background with no user present to press the relevant key strokes.
You can use a double redirection (">>") to append to a file instead of overwriting it. If the file doesn't already exist, it will be created.
student@debian:~$ ls output.txt ls: output.txt: No such file or directory |
Make sure that the file does not already exist in your home directory.
student@debian:~$ echo "test" >> output.txt student@debian:~$ cat output.txt test |
student@debian:~$ echo "test again" >> output.txt student@debian:~$ cat output.txt test test again |
The above two steps will prove that the append function actually does create the file if it does not already exist.
A pipe ("|") directs the stdout from one process to the stdin of another:
Note that stderr is _not_ passed through the pipe!
student@debian:~$ ls dataset2 | grep "txt" fight.txt flight.txt org.txt singularity.txt three.txt vernor.txt vinge.txt student@debian:~$ _ |
This type of pipe is called an "un-named pipe". The un-named pipe uses a temporary buffer type of action to pass the stream of data through.
You can also use "named pipes". We briefly mentioned them earlier in this course; they are also known as FIFO buffers.
Named pipes work exactly the same as unnamed pipes, where the stdout from one process is fed into the stdin for another process.
You can use the mkfifo command to create such a file, and you can then simply use the redirection symbols to put data in, or take it out. As the name implies, the data is read First In, First Out.
student@debian:~$ mkfifo foop student@debian:~$ ls -l foop prw-r--r-- 1 mwest mwest 0 Jan 13 23:26 foop| student@debian:~$ echo "testing the named pipe" > foop |
Ok, now go and open up another terminal. You can do this by holding down the Alt key and pressing F2. Once there, log in, and then type the following:
student@debian:~$ cat < foop testing the named pipe student@debian:~$ _ |
If you switch back to your original terminal window (press alt-f1), you should see that your shell has now returned back to your prompt. This is because your previous "cat" command took the contents out of the pipe, and so your original "echo" command was able to complete.
Check if the file called "foop" still exists as a named pipe in your directory.
Experiment with this one a bit, it can be quite fun!