Two important things:
- In your examples
echo runs always before cat.
- Each redirection
> file_test creates an independent open file description.
Your first example is simple: echo writes to file_test, then cat copies the content of file_empty to file_out.
In the second and in the third example file_test is opened and truncated twice. First the "outer" > file_test opens and truncates the file, then the other > file_test opens and truncates the file for echo; only then echo runs, finally cat runs.
In effect echo writes to file_test from the beginning of the file, and cat writes to file_test independently from the beginning of the file. The two tools do not share an open file description, so the act of writing by echo does not move the position in the file for cat. The latter tool (over)writes to the file from the beginning, not from where echo finished.
Specifically, in the second example echo writes test to the file, then cat puts something in the file from its beginning, overwriting test.
In the third example echo writes test to the file, then cat puts an empty string in the file from its beginning, overwriting nothing (as the size of the empty string is zero bytes).
To better see what happens, consider this:
(echo "1234567890interesting" > file_test; < file_in cat) > file_test
First echo writes 12… to the file, then cat puts something in the file from its beginning, overwriting 12…89 with something and 0 with the terminating newline character from file_in (I'm assuming the line that says something is properly terminated inside file_in). The content of file_test is now:
something
interesting
(with a terminating newline character after interesting, added by echo in the first place).
It is different with
(echo "1234567890interesting" > file_test; < file_in cat) >> file_test
because >> is essentially "always seek to end of file". This time cat writes from where echo finished, because at the time this is where the file ends. Try it. The result is:
1234567890interesting
something
(with a terminating newline character from file_in).
Also if the two tools actually share an open file description (created with >) then echo will move the position in the file for cat:
(echo "1234567890interesting"; < file_in cat) > file_test
The result is again
1234567890interesting
something
(with a terminating newline character from file_in).