Pages

Monday, 2 October 2023

Bash IO redirections are processed one by one, from LEFT to RIGHT

TLDR;

Look at below two command lines.

$ non_exist_command 2>&1 > log.txt
$ non_exist_command > log.txt 2>&1

If you are super clear of the differences between the above two command lines, go away!
If not, read on.

Explanation

$ non_exist_command > log.txt 2>&1

In Bash, the IO redirection operators are processed one by one from left to right. Take the first command line as an example here. When shell starts a new process for this command line, at the very beginning, the file descriptor table is like below.

---------------------------------------------------
| file descriptor       |  the device pointed to  |
---------------------------------------------------
|       0               |    /dev/console         |
---------------------------------------------------
|       1               |   /dev/console          |
---------------------------------------------------
|       2               |   /dev/console          |
---------------------------------------------------

After processing the first IO redirection, 2>&1, the table becomes

---------------------------------------------------
| file descriptor       |  the device pointed to  |
---------------------------------------------------
|       0               |    /dev/console         |
---------------------------------------------------
|       1               |   /dev/console          |
---------------------------------------------------
|       2               |   /dev/console          |
---------------------------------------------------

You can see here, actually nothing changed. It's because the device refereced by fd=1 at this moment is /dev/console. 

Then bash processes the second IO redirection, > log.txt.

---------------------------------------------------
| file descriptor       |  the device pointed to  |
---------------------------------------------------
|       0               |    /dev/console         |
---------------------------------------------------
|       1               |   ./log.txt             |
---------------------------------------------------
|       2               |   /dev/console          |
---------------------------------------------------

$ non_exist_command > log.txt 2>&1

When shell starts a new process for this command line, at the very beginning, the file descriptor table is like below.


---------------------------------------------------
| file descriptor       |  the device pointed to  |
---------------------------------------------------
|       0               |    /dev/console         |
---------------------------------------------------
|       1               |   /dev/console          |
---------------------------------------------------
|       2               |   /dev/console          |
---------------------------------------------------
After processing the first IO redirection, > log.txt, the table becomes


---------------------------------------------------
| file descriptor       |  the device pointed to  |
---------------------------------------------------
|       0               |    /dev/console         |
---------------------------------------------------
|       1               |    ./log.txt            |
---------------------------------------------------
|       2               |   /dev/console          |
---------------------------------------------------

Then bash processes the second IO redirection, 2>&1. At this moment, fd=1 is referencing log.txt. So after 2>&1, fd=2 refreces log.txt as well.


---------------------------------------------------
| file descriptor       |  the device pointed to  |
---------------------------------------------------
|       0               |    /dev/console         |
---------------------------------------------------
|       1               |    ./log.txt            |
---------------------------------------------------
|       2               |    ./log.txt            |
---------------------------------------------------




No comments:

Post a Comment