You can read about this syntax in the bash man page under Process substitution:
>(list). The process list is run with its output connected to some file in /dev/fd. The name of this file
is passed as an argument to the current command as the result of the
Look at the output of this command which does not do any redirection:
echo >(echo hi >/tmp/a) >(echo lo >/tmp/b)
it is (on my system):
So you must read
1> >(...) as
>(...). The second part gets replaced by
/dev/fd/63, and we then have
1> /dev/fd/63 so we redirect stdout to file descriptor 63.
bash runs the command inside
>(...) in a separate process, and connects the stdin of that process to file descriptor 63. Check out this example:
echo hello > >(cat -n)
The stdout of the echo is piped into the input of
cat -n and you get:
+ echo hello
++ cat -n
Perhaps what you are missing is that when you have a file descriptor (fd) for a file, and then fork the process (which bash is doing with
>(...)), you can inherit the same fd in the new process. So the 2 processes share the same fd. Moreover, there is only one file offset for an fd, so if process 1 writes 3 characters to the fd, then the offset moves from 0 to 3. If process 2 then writes 5 characters to the fd, the data is placed at offset 3 and the offset becomes 8. If process 1 writes another character it is placed at offset 8, and so on. This is how the two
tee commands in your question manage to write to the same file
all without overwriting each other.
>&3 does not create a new fd; it simply closes the current stdout fd 1, then renumbers fd 3 to fd 1. So there is still only one fd for the two processes, even if the number now seen by each process is different (see
man dup2 for the underlying system call).