7

I have file1, file2, file3.


file1 contains 1

file2 contains 2

file3 contains 3

I use command

cat file1 > file2 > file3

Results in:

file1 1

file2 (contains nothing)

file3 1


Why does anything along this line get destroyed? Basically what am I not seeing behind the scenes?

(Side notes using "append" >> is even weirder)

  • Check out Muru's answer below if you want an answer on how the command actually functions on a lower level! – No Time Feb 4 '15 at 15:30
14

Redirections in Bourne/POSIX-style shells such as bash, dash, ksh, etc.

processed in the order they appear, from left to right

> x opens and truncates file x, and sets the file descriptor that writes into x as standard output. Your command:

cat file1 > file2 > file3

Will:

  1. Open and truncate file2
  2. Set standard output to write to that file descriptor
  3. Open and truncate file3
  4. Set standard output to write to that file descriptor
  5. Run cat file1

The end result is that standard output points into file3 at the time cat runs. Both file2 and file3 have their current contents erased, and file3 gets the output of cat (the contents of file1) written into it.


If you want to split output into multiple streams written into separate files, you can use tee:

cat file1 | tee file2 > file3

Other shells (notably zsh) behave differently, and your command would have the result you probably expected: both file2 and file3 would have the contents of file1.


Note that cat isn't necessary here; < input redirection would do the job just as well.

  • I wish I could accept both your answer and @muru as for zsh it does do it the way I expected originally. – No Time Feb 4 '15 at 5:51
  • While cat may not be necessary, some command that reads from the input file is. < inputfile > outputfile will just truncate the output file, it won't copy the input file to it. – Barmar Feb 4 '15 at 19:11
  • It's a preemptive UUOC ward for the tee command. < x > y actually does work in zsh, though. – Michael Homer Feb 4 '15 at 19:56
  • I remember alta vista . . (link contains reference to alta vista) It almost seems like a formula would work here to explain the interaction, like it must be every other > or < must be opposite to keep the data flowing. But I really don't know for sure and too tired to think. – No Time Feb 6 '15 at 23:52
9

When you redirect an fd multiple times, all redirections get performed, and the last one sticks:

$ strace -f -e open bash -c 'cat file1 > file2 > file3'
open("/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 3
...
[pid 20508] open("file2", O_WRONLY|O_CREAT|O_TRUNC, 0666) = 3
[pid 20508] open("file3", O_WRONLY|O_CREAT|O_TRUNC, 0666) = 3
...
[pid 20508] open("file1", O_RDONLY)     = 3

So, file2 was opened and truncated, and then file3 was opened.

  • so this actually runs the command through as it would be through c ? – No Time Feb 4 '15 at 5:54
  • @NoTime if you're talking of strace, it runs the command the way it normally runs, but lists the system calls made. Those can be made in any language that the system api is available in. Strace is like a debugger in that respect. – muru Feb 4 '15 at 5:56
  • That is awesome, that would probably have answered my question more or less right there. So the basically it's like setting a variable 200 times, it really doesn't matter what the first 199 were. (Just me trying to do analogy for myself) – No Time Feb 4 '15 at 6:01
  • @NoTime yes, that's how I see it too. And that's why zsh's behaviour, while certainly more useful, strikes me as counterintuitive. – muru Feb 4 '15 at 6:20
  • I think your answer is great. I am not sure it will be useful to as many people,(it was super effective for me) so I didn't accept it (sorry). But I upvoted one of your other great questions. – No Time Feb 4 '15 at 15:33

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.