Not quite. Picture a UNIX process as a sort-of garden hose for data: you pour something in on the top and something rins out at the bottom. So far, it should be quite clear. Now, where the UNIX process differs from the garden hose is that it doesn't have only one outlet but several of them. So you pour something in above and something comes out on several places at the bottom.
The places where something gets in (=> input) or out (=>output) of the process are called "I/O descriptors" because such an I/O descriptor really is just a - very generalised - intake/outlet for data. To really get input or generate output the I/O-descriptor has to point to some place where the output can be either displayed or printed. Taking again the garden-hose analogy: the I/O-descriptors are just the openings in the hose. Without anything going in or out they are useless. So you have to connect something to the input (i.e. the water tap), only then the hose will do something. Equally if you do not point the bottom opening to something the water just spills out and is lost. If you point it to a bucket it can be collected in it and hence used.
The same is true for these I/O-descriptors: per default there are three of them: <stdin>, <stdout> and <stderr>. And also per default all are pointing to the terminal a process was started at. That means <stdin> is connected to the keyboard (the input device of the terminal) and the others are connected to the display (the output device of the terminal). Two things are worth mentioning: in principle it is possible to use any output descriptor for any kind of data but there is a convention (hence the name of these) that "normal data" goes to <stdout> and diagnostic messages go to <stderr>. Also, per default there are three such I/O-descriptors open: 0 is <stdin>, 1 is <stdout> and 2 is <stderr>. More (IIRC up to 9) you can create on purpose. For instance:
# ls -l /home /does/not/exist
ls: cannot access '/does/not/exist': No such file or directory
/home:
total 20
drwx------ 2 root root 16384 Jul 22 2018 lost+found
drwxr-xr-x 42 bakunin bakunin 4096 Feb 17 00:55 bakunin
The line "cannot...." is a diagnostic message and went to <stderr>, the rest is normal output of the ls
command. Either of these channels can be redirected to somewhere else - in this case to /dev/null
, a file that just devours unwanted output:
# ls -l /home /does/not/exist >/dev/null
ls: cannot access '/does/not/exist': No such file or directory
# ls -l /home /does/not/exist 2>/dev/null
/home:
total 20
drwx------ 2 root root 16384 Jul 22 2018 lost+found
drwxr-xr-x 42 bakunin bakunin 4096 Feb 17 00:55 bakunin
# ls -l /home /does/not/exist >/dev/null 2>/dev/null
Do you see a pattern? When i wanted to redirect <stdout> (I/O-descriptor 1) i wrote:
# ls -l /home /does/not/exist >/dev/null
which is a shortcut for the equally correct:
# ls -l /home /does/not/exist 1>/dev/null
when i wanted to redirect <stderr> or I/O-descriptor 2 i wrote:
# ls -l /home /does/not/exist 2>/dev/null
Now, suppose i want to redirect both these output channels to the same place. I could write i.e.:
# ls -l /home /does/not/exist >/some/file 2>/some/file
But this might be prone to typos as i could write different filenames as they become longer and longer. Therefore i could also write:
# ls -l /home /does/not/exist >/some/file 2>&1
The first part you know already: > /some/file
means redirect <stdout> to /some/file
. The second part 2>&1
means redirect <stderr> to where <stdout already points (whereever that is).
You can redirect other output channels the same way. i.e. 4>&6
means: redirect I/O-descriptor 4 to where I/O-descriptor 6 is pointing at right now. These redirections are read from left to right. The respective output stream doesn't even have to transport any data to be redirected. It could be used to just "store" the redirection of another I/O-descriptor that is being redirected.
You can also give general redirections for complete code blocks with the exec
command:
command1 # nothing redirected
exec 3>/some/file # everything leaving via I/O-descriptor 3 is now landing in /some/file
command2
command3
exec 3>&- # close this redirection
command4 # nothing redirected again
Suppose some I/O-descriptor is redirected to a location you do not know. You want to temporarily redirect it to somewhere else and then redirect it back to where it was. It is not possible to directly find out where it points at, but you can use another I/O-descriptor to "store" the location by letting it point to where this I/O-descriptor already points, then restore the other one back to that place. Watch I/O-descriptor 3 being manipulated in the example:
exec 9>&3
command 3>/some/place
exec 3>&9
I let 9 point to where 3 points at, then redirect 3 and finally redirect 3 to where 9 now points at, because that is where 3 has pointed to before.
Also notice that up to now we always used >
for ou redirections. If the redirection is to a file this file will be deleted and then recreated that way. You might want to preserve what is in this file, though. Use >>
instead in this case, then.
Here is a way to to make sure a file exists but is completely empty:
: >/some/file
:
is the "null-command" and does (and outputs) nothing. Redirecting this to the file truncates it to zero or creates it with zero length if it doesn't exist already.
I hope this helps.
bakunin