cat somefile >file1 >file2
Without redirections cat somefile would inherit stdin from the shell. Usually stdin of a shell is not closed, it already points to some file. A terminal is also a file. When you run cat somefile in an interactive shell whose stdout is your terminal, the output of cat goes to the terminal. In general the stdout of the shell may be something else, irrelevant, cat will inherit it anyway.
What cat somefile >file1 does is it makes the shell:
- try to open
file1 for writing (it creates the file if it's not already there) and to truncate it to zero size (if possible); this happens before cat is started;
- set up
file1 as stdout for the future cat, so the cat will use file1 instead of what it would use without the redirection (you don't expect cat somefile >file1 to also write to your terminal, right?).
The redirection redirects. :) The current direction is "to the terminal", the new direction is "to file1". The new direction is taken instead of the current direction and the new direction becomes current.
The shell parses redirections from left to right. In case of cat somefile >file1 >file2 the shell first handles >file1 in the way described above. Then it handles >file2 in the same way: it opens and truncates the file, and sets up "to file2" for the future cat instead of the current direction which at this point is already "to file1". This way "to file2" replaces "to file1" and becomes current, exactly like "to file1" replaced "to the terminal" a moment ago.
You can add more >fileN redirections and each one will be handled in the described way. Assuming each one succeeds, the last one will win. In your case >file2 wins.
After all the redirections are handled, cat is started. Your cat sees file2 as its stdout and it's not even aware file1 was involved in any way. The truncation of file1 is a "side effect", it's only because >file1 has been parsed by the shell, it has nothing to do with cat.
You can use this mechanism to create/truncate one or more files: : >file1 >file2 … will try to truncate the files. : is a no-op, it doesn't even use its stdout. Creating and truncating happens when the shell handles the redirections before starting :.
This is how output redirections work in sh and compatible shells. The MULTIOS option in zsh (see this other answer) is different: the first redirection replaces the old direction (e.g. the terminal) while consecutive redirections add directions. How it happens under the hood, I won't elaborate. I just want to point out that the behavior you observed emerges from the fact in sh (or in a compatible shell) each >fileN is handled independently, one after another; but in zsh there's a mode where it treats multiple output redirections more like a unit.
>redirects the output to a file, period. Usetee(1)if you want to duplicate output to a file and send it on.cat somefile >file1 3>file2 4>file3. This means you start the program with two extra files opened as fileno 3 and fileno 4. Of course,catwill ignore those, but it can be useful if you want to have different log files, for example, or you're somehow splitting the input in 3 parts, etc.