I often see other people’s shell scripts followed by a 2>&1
, and have never bothered to look deeper, so today this topic will be the starting point to expand and learn about the topic of redirection in the linux shell.
Special things
First, let’s look at some special things in linux to lay the groundwork for the rest of the content.
Special files
/dev/null
empty, you can import garbage content into it and it will disappear/dev/zero
zero, you can read endless zeros from it/dev/urandom
random numbers, you can read endless random numbers from it/dev/stdin
standard input stream/dev/stdout
Standard output stream/dev/stderr
standard error output stream
We can see that the last three files are actually links to the kernel’s file descriptors 0\1\2.
Special file descriptors
There are three special file descriptors (File descriptor
or fd
) in the Linux shell:
- fd
0
is the standard input:stdin
- fd
1
is the standard output:stdout
- fd
2
is the standard error output:stderr
With these three special file descriptors we can control the input and output streams.
Redirects
We often come across the symbol >
, called a redirect, but there is another symbol >>
that has a similar function, with a small difference between them.
>>
is an overwrite method.>>
is an append method.
The following contents will all be
>
as an example,>>
has no other difference except that the content is appended, so I won’t repeat it.
Using redirects
Redirecting to a file
Let’s first look at the most basic use of redirection, where we redirect the output of the echo
command to a file.
|
|
The result of the execution is as follows.
Here it is redirecting stdout to the file a.txt, which is equivalent to the following command.
|
|
The result of the execution is as follows.
Here we see that the redirection symbol >
defaults to redirecting stdout
, which is fd 1
, to somewhere else.
If we want to redirect the standard error output stderr
, we just need to change the file descriptor 1
in the above command to the standard error output file descriptor 2
.
Redirecting to file descriptors
In some cases stderr
is programmatically controlled to write to the error log, so if we want to display the error on the screen while the command is running, we need to redirect the error output to the standard output stream.
Let’s try it first, here we don’t find a suitable command, so we take the ls
command to look at a directory that doesn’t exist, which will generate an error output.
Here the error is output to the screen by default, but I haven’t found a better program yet, so let’s assume it won’t be output to the screen.
|
|
Our guess here is to redirect stderr
to stdout
, so we write 2>1
, let’s see if that works?
We see that instead of output, a file 1
is generated in the current directory, which means that if we just write >1
it will be treated as a redirect to the file 1
.
At this point, our &
comes into play.
>&
is the syntax for redirecting a stream to a file descriptor, so just now we should specify that we want to redirect to fd 1
, which is &1
.
|
|
Execution results.
Here we can play independently.
Redirects the standard output to the standard error output.
|
|
or
|
|
We can even play a little more complicated.
Here the file descriptor 9
will be generated automatically, but removing the brackets will prompt an error.
In bash >4.0, a new redirect syntax has been introduced.
I haven’t learned this way of writing yet, I’ll update it later when I learn it
Formatting output
A little bit of high-end usage.
For formatting output, redirecting the standard output and error output streams to different processes, and finally aggregating them.
A new version of the grammar with the same effect.
Merge files
Merge output files m and n: n >& m
.
Merge input files m and n: n <& m
.
Input boundaries
Take as input the content between the start tag and the end tag: << tag
.
Example.
Its function is to pass the content (document) between two EOFs as input to command.
Note.
- The delimiter at the end must be written in top space, with no characters before it and no characters after it, including spaces and tab indents.
- Spaces before and after the starting delimiter are ignored.
About overwriting
If we set bash with set -o noclobber
, then bash will not overwrite any files that already exist, but we can bypass this restriction with >|
.
Let’s look at the default case first
|
|
As expected, each redirect overwrites the original file
We set the noclobber
flag below
set -o noclobber
Then repeat the above to try it out.
|
|
We saw the bash prompt that it cannot overwrite an already existing file, and the actual result is the same.
How can we do the bypass? Let’s try >|
instead of >
.
We find that we can overwrite the files that already exist at this point, and we look at the current settings.
noclobber
is indeed turned on, so >|
does bypass this restriction.
Use set +o noclobber
to turn off this restriction and prevent it from affecting our later use of
Other tidbits of knowledge
Redirecting to one place
If we want to redirect stdout
and stderr
to the same place, how should we write it?
Which of the following two is the right one?
ls -ld /tmp /tnt 2>&1 1>a.txt
ls -ld /tmp /tnt 1>b.txt 2>&1
Verify it.
The first way to write
The second way to write
We can see that the second way of writing is correct.
Similarly, the following way of writing is also correct.
|
|
Nested
what happens if we redirect stderr
to stdout
, and at the same time redirect stdout
to stderr
?
Will such nesting cause a crash?
Try it.
We find that it all comes out of the standard output.
And the other way around?
We find that none of it comes out of the standard output, it comes out of the standard error output
That means
a>&b b>&a
is written in this nested way, and b is the output.
Read more
If you want to understand the functionality, check the official documentation with the following command
man -Len -Pless\ +/^REDIRECTION bash
Reference for this article: stack overflow