When we talked about linux shells ( Hi linux shell, nice to meet you! ) we mentioned programs, how do they are called and specific commands.
Program execution, in Linux as in any other platform, is a sequence of operations that are ran in a given way based on the logic of the program and you can imagine the program as a black box, that you don’t necessarily need to know what it does, as we want to concentrate on what is around it.
To better understand what I’m saying, consider a diagram like the one shown below:
Having the program as our black box, we can imagine three main fluxes of data coming in and out from it:
- STDIN – Input – Associated file descriptor on startup: 0
- STDOUT – Output – Associated file descriptor on startup: 1
- STDERR – Error – Associated file descriptor on startup: 2
As you can see, the program takes an input, let’s say keystrokes from your keyboard, a file, the output of something else, elaborates it in a simple or complex way, and it produces an output and/or errors.
The default output is the shell or terminal that you are using.
Eww..what about an example ?
It could be confusing at the beginning but with some examples it will become clear.
Starting from something that is familiar and very basic, let’s try to play with ‘cat‘ command. This command is used to concatenate content and it is one of the best examples to understand how streams work.
I’ll assume that you know how to use cat, it is very basic, if you don’t, checkout the manual – man cat
Well, if you just type the command, it will start waiting for something, that is to say, it is waiting for you to input something with your keyboard and as soon as you will type anything, it will redirect to the de Save fault output, the terminal, everything that you typed:
As you can see, I highlited what is the input and what is the produced output.
When you try to cast the command on an existing file, the file becomes the input, and its content is the output:
Above command is equivalent to:
With < being the operator that relates to STDIN and tells that the command must use the given file as Input.
This is what happens if you try to cat a non-existing file:
The reason why you see the error on the screen is because, by default, the errors (STDERR) are directed to console exactly like (STDOUT), so if you try to open a non-existing file, it wil show you up that something went wrong.
So…can I manipulate this in any way?
With great power comes great responsibility… Of course you can!
I will now show you how you can play with redirection, trying to cover the most common cases and shortcuts.
Assume that you want to send the output of a command to a file, I will show you how you can easily do that by taking cat again as an example.
The operator that is used to redirect output is > and it is very intuitive, because it refers to a direction. In the paragraph above, I wrote the association with file descriptors, keep it in mind because we will use them in the next examples.
Let’s write the output of our keystrokes into the file myoutput:
The result will be this:
Basically, you are telling to the shell to take the output of the command and redirect it into the file.
Operator > is a shortcut to imply 1> that is the file descriptor for STDOUT, so you can achieve the same result by writing:
By opening the file, you can quickly check it by yourself.
Every command can throw errors during execution, and you may need to separately have a trace of it, so you could be facing the following scenario:
- Redirect STDERR to a file
- Redirect STDOUT to a file and STDERR to another file
- Redirect STDOUT to a file and STDERR to the same file
- Redirect STDOUT to a file and trash STDERR
I’ll guide you throught all of these occurrences. Note that although the file descriptor was not needed when referring to STDOUT (1), it needs to be explicit when referring to STDERR (2), so the syntax could be a bit tricky at the beginning.
Redirect STDERR to a file
In the first case, you will have to take what you did for redirecting STDOUT and combine it with STDERR redirection.
Taking cat as an example, we saw that casting it to a non-existent file would lead to this error:
Now let’s redirect an error to a logfile:
Finally, let’s see what’s the result:
We successfully redirected the error in a logfile.
Redirect STDOUT to a file and STDERR to another file
In order to cover the second we will try to concatenate an existing file, let’s say testfile, and a non-existent file, let’s say nonexistantfile, redirecting the STDOUT to a file called logOutput and STDERR to a file called logError:
This is what we will get:
Redirect STDOUT to a file and STDERR to the same file
Most common case, a sort of trace of every event logged in the same file, but the syntax becomes a little bit tricky.
Achieving this result needs that the STDERR redirects to the same stream referenced by STDOUT.
Here’s it is in action:
Those familiar with C language, you could recognize the syntax (who said pointer?) as in fact, the ‘2>&1’ stuff can be read as “redirect STDERR (2) to the location referenced by STDOUT (1)” the ‘referenced by’ part is the human translation for ‘&’.
The output is the following:
Redirect STDOUT to a file and trash STDERR
One might want to ignore errors, especially when dealing with commands executed recursively over directories, files, and so on, that could lead to insignificant errors about permissions, file not found or similar.
There is a special place where you can put unneeded/unwanted stuff, and it is /dev/null. It is a ‘virtual’ file, that doesn’t store anything, so everything is redirected to it is lost.
You can trash the STDERR output by redirecting it to /dev/null:
Nothing will be printed on the screen and our output log only contains the output of the function!
Now you successfully learned how to play with basic output redirection, of course this can lead to more complex scenarios, where the output of something becomes the input for something else, but we will cover it maybe with some samples.
If you liked the post, share it with your friends and colleagues!