0

This question already has an answer here:

I am reading this documentation which gives the following examples about redirection and file descriptors.

ls > dirlist 2>&1

will direct both standard output and standard error to the file dirlist, while the command

ls 2>&1 > dirlist

will only direct standard output to dirlist. This can be a useful option for programmers.

Are these examples the wrong way round? It seems to me the second example "will direct both standard output and standard error to the file dirlist" while the first example "will only direct standard output to dirlist".

If I'm wrong about this (...probably...) can someone explain the logic of these 2 examples clearly?

marked as duplicate by Gilles bash Nov 22 '16 at 23:36

This question has been asked before and already has an answer. If those answers do not fully address your question, please ask a new question.

  • 1
    Side note: The Bash guide you've linked to is heavily not recommended. Instead, check out the Wooledge Bash Guide. – Wildcard Nov 22 '16 at 2:17
1

First of all, you need to understand the n>&m syntax. this is a duplication operation, meaning copy m to n. check out section "3.6.8 Duplicating File Descriptors".

I had the same doubt as you when I studied the article. So I can try to explain it to you:

ls > dirlist 2>&1 

with the above command, you first redirect the output to dirlist by > dirlist. 2>&1 means copy file descriptor 1 to 2, in other words make fd2 a copy of fd1. Now fd1 is already pointed to dirlist, making fd2 a copy of fd1 means fd2 also points to dirlist. As a result, fd1->dirlist, fd2->dirlist.

ls 2>&1 > dirlist   

with this, you first make fd2 a copy of fd1 which is still the terminal, so fd2->terminal. then you redirect fd1 to dirlist. as a result, fd2 -> terminal, fd1->dirlist.

  • Thank you so much. I think the part that is confusing me is "2>&1 means copy file descriptor 1 to 2, in other words make fd2 a copy of fd1". I had the impression that 2>&1 meant exactly the opposite: i.e. copy file descriptor 2 to 1 so that the contents of 1 include the contents of 2. Reading left to right i can't see the logic of how 2>&1 ("take fd2 and send it to fd1", as i am reading it) actually means "make fd2 a copy of fd1". What am i missing? – penname Nov 24 '16 at 20:33
  • @penname its just how the syntax is, you just need to remember it. Check out section "3.6.8 duplicating file descriptor" of this page this page: gnu.org/software/bash/manual/html_node/Redirections.html – David Dai Nov 24 '16 at 22:51
0

The directions are processed left to right.

ls > dirlist 2>&1

makes the shell which will eventually turn itself into ls, do the following system calls (error checking omitted for brevity).

/* Handle > dirlist */
int temp_fd = open("dirlist",O_WR);  /* Open dirlist for output */
dup2(temp_fd, 1); /* Make file descriptor 1 (stdout) point to dirlist */
close(temp_fd);  /* Don't need this other file descriptor for dirlist */
/* Handle 2>&1 */
dup2(1,2); /* Make fd 2 be a copy of fd 1, which points to dirlist */

So first fd 1 is changed, and then fd 2 is changed.

Conversely ls 2>&1 > dirlist does

/* Handle 2>&1 */
dup2(1,2); /* Make fd 2 be a copy of fd 1, the original stdout */
/* Handle > dirlist */
int temp_fd = open("dirlist",O_WR);  /* Open dirlist for output */
dup2(temp_fd, 1); /* Make file descriptor 1 (stdout) point to dirlist */
close(temp_fd);  /* Don't need this other file descriptor for dirlist */

A different way to look at it is as just assignments. Originally fd1=initial_stdout, then

/* ls > dirlist 2>&1 */
fd1=to_dirlist
fd2=fd1 (i.e. to_dirlist)

/* ls 2>&1 > dirlist */
fd2=fd1 (i.e. initial_stdout)
fd1=to_dirlist.

Or you can say copy by value rather than copy by reference.

  • Thank you so much for this answer. I need to go through it more slowly, and then i may have some questions. In the meantime, can i ask: what tool did you use to view the system calls? Knowing this depth of detail is a big help. – penname Nov 24 '16 at 20:36
  • @penname, I didn't look at system calls, this is just knowledge I have acquired over the years (which means it may be wrong!). If you want to look yourself, then the most common tool to use would be strace -f -o /tmp/strace/out ..... A newer tool would be sysdig.org, or even the bpf stuff in the linux kernel. To show my age, truss for solaris would be the correct tool. – icarus Nov 25 '16 at 2:00

Not the answer you're looking for? Browse other questions tagged or ask your own question.