9

This question already has an answer here:

I have this command:

cat somefile >file1 >file2

After I executed this command I can't figure out why file1 has nothing in it. It should have the output of the first file (somefile), but nothing is in it.

Can you explain to me why it does not copy or write my output from somefile? (file2 contains my output, but file1 contains nothing)

marked as duplicate by jimmij, roaima, don_crissti, vonbrand, slm Jan 3 '16 at 1:56

This question has been asked before and already has an answer. If those answers do not fully address your question, please ask a new question.

  • A > redirects the output to a file, period. Use tee(1) if you want to duplicate output to a file and send it on. – vonbrand Jan 3 '16 at 1:21
15

I think there's a difference between how you think shell redirection works and how it really does.

You cannot redirect the output of the shell multiple times and expect it to be redirected to all the locations you've specified. Instead, it will only be redirected to the last location, which in your case is file2. The answer by Chaos provides a decent explanation on how such I/O Redirection works.

What you really want to do is:

$ cat example.txt | tee file1 > file2

tee is a program that reads from the standard input and writes to multiple file descriptors. One of them is always the standard output. So we use tee to write the output to file1 and then redirect its stdout to file2.

Also, based on suggestions in the comments, this is a better way to do what you're looking for:

$ tee file1 > file2 < example.txt

This approach has the advantage that it redirects the stdin instead of trying to read over a pipe. This means that the shell now needs to spawn one less process. It also eliminates what is known as "Useless use of cat".

  • 3
    Better, tee file1 >file2 <example.txt – roaima Oct 9 '15 at 20:31
  • 1
    I much prefer the cat ... | tee approach. Maybe the cat is useless, but it is much easier for me to follow. Is your system really so constrained that firing off an extra cat process is going to be an issue?? – Brandin Oct 10 '15 at 13:26
  • 1
    I agree that the cat ... | tee approach is cleaner. Also, a system is barely ever so constrained that it cannot handle the extra call to cat. It's however another option. – darnir Oct 10 '15 at 14:04
  • If you really want a clean tee command, write it as < example.txt tee > file1 file2 This can be translated to the human saying of "Using example.txt tee it to file1 and file2" – Ferrybig Oct 10 '15 at 15:20
  • 1
    @roaima: I presume the cat is not really a UUOC but a placeholder for some more complicated command. (Anybody who actually wanted to copy the contents of a file to two other files would just use cp twice.) Omitting it obscures the general principle being used. – Nate Eldredge Oct 10 '15 at 19:03
9

What you did, is called I/O-Redirection. >file redirects the standard output (stdout) to the given file. In you case you did that 2 times. The shell doesn't handle a redirection of the same output multiple times .

In this case:

cat somefile >file1 >file2

The shell processes the redirections before the command (cat somefile) is executed. That means the > truncates file to zero length, because you override the files content. The file must be empty before the shell can execute the command. This is done with both > redirections.

Now, the second one (>file2) overrides the first one (>file1), because the shell processes the redirection in order of appearance. So, the last one is the one that will effectvely be used. The output of cat somefile will therefore be redirected to file2 and file1 will be truncated to zero length.


Redirecting stdout to multiple processes/files can be done with tee like this:

cat somefile | tee file1 file2 file3 fileX

This will print the contents to stdout and to all files given as paramters.

  • Oh, it handles redirection of the same output multiple times. It's just doesn't handle it the way the OP expected it to. ;-) (You actually describe well how it's handled.) – The Sidhekin Oct 9 '15 at 21:52
  • 3
    It might be better to do something like tee <somefile >file1 file2, since cat somefile | tee file1 file2 file3 fileX dumps the contents of somefile to your terminal and doesn't really need the cat call. – user62251 Oct 10 '15 at 1:34
2

In zsh with MULTIOS option set, you can use:

cat somefile >file1 >file2

as in this case, zsh action similar to tee.

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