Shell – Command with pipeline and redirection

io-redirectionpipeshell

What is the order of commands executed which have both pipeline and output redirection in it?

Say we do the following:

Charles@myzone:/tmp$ mkdir /tmp/testdir      
Charles@myzone:/tmp$ cd /tmp/testdir   
Charles@myzone:/tmp/testdir$ touch file1 file2  
Charles@myzone:/tmp/testdir$ ls | wc -l
2
Charles@myzone:/tmp/testdir$ ls | wc -l > ls_result
Charles@myzone:/tmp/testdir$ cat ls_result
3

I know that if you do ls > result then result will contain the name of itself because the shell will do something like

1) create/open file named result
2) set the fd of result to be stdout
3) exec ls

I was expecting ls_result to have value 2, but it's 3.

Question

How is the command ls | wc -w > ls_result above executed ?

Is it equivalent to (ls | wc -w ) > ls_result?

Some links with concerning information ? (I've looked up the bash manual)

Best Answer

utility1 | utility2 >output

is not equivalent to

( utility1 | utility2 ) >output

but to

utility1 | { utility2 >output; }

The two utilities are started pretty much the same time, which means you would expect your command to sometimes return 3 and sometimes 2.

Example:

$ { [ -f test ] && echo exists >&2; } | { echo >test; }; rm test
$ { [ -f test ] && echo exists >&2; } | { echo >test; }; rm test
$ { [ -f test ] && echo exists >&2; } | { echo >test; }; rm test
exists
$ { [ -f test ] && echo exists >&2; } | { echo >test; }; rm test
exists
$ { [ -f test ] && echo exists >&2; } | { echo >test; }; rm test
$ { [ -f test ] && echo exists >&2; } | { echo >test; }; rm test

The above shows that the file created by the right hand side of the pipeline is sometimes detected by the left hand side of the pipeline.

Related Question