Linux command substitution order

The genesis of the issue you are seeing is due to the way tokenization happens of a command line. In this particular case, much before the $(echo 'echo | tac') is expanded, the shell has already figured out that you intend to run a command (echo {…}) and pass it's output via a pipe (|) to another command (xargs -n 2 $(…)).

Then in the next stage does the filling in of $(…) and brace expansion {…} happens to generate the actual commands to be run. And in this stage if it results in a pipe character, so what, it's too late and it's clearly missed the bus.

Now it will be treated as not as a special metacharacter, but will be included in the xargs command line as just any ordinary (=> non-metachar) char.

Should you want to take another shot at it, then you need to eval it.

eval "echo {0..9} | xargs -n 2 $(echo 'echo | tac')"

This will output what you expect.


besides Roman said, your commnand should be like this

echo {0..9}| xargs -n 2 | tac

this produces

8 9
6 7 
4 5
2 3
0 1

with the pointless $(echo 'echo') this causes the error

PS. For the long answer, | redirects the output from one command to the next one, so echo {0..9} produces:

0 1 2 3 4 5 6 7 8 9

xargs -n 2 takes that input and produces

0 1
2 3
4 5 
6 7
8 9

and finally tac takes that input and produces the reverse expresion:

8 9
6 7
4 5
2 3
0 1

I hope this is a bit clearer.

EDIT:

echo {0..9} | xargs -n 2 $(echo 'echo | tac')
+ echo 0 1 2 3 4 5 6 7 8 9
++ echo 'echo | tac'
+ xargs -n 2 echo '|' tac
| tac 0 1
| tac 2 3
| tac 4 5
| tac 6 7
| tac 8 9

This is the command that you are sending to bash with your initial sintax, it's pretty clear what's happening, at the end you are sending xargs -n 2 echo '|' tac