G.D.
G.D.

Reputation: 177

Why is file2 empty after 'cat file1>file2>file3'?

I am trying to execute the following command on UNIX.

$ cat file1>file2>file3

In the scenario where only the file1 is present, what I think should happen is:

What actually happening is that:

Can anyone explain why this happens?

Upvotes: 3

Views: 7352

Answers (4)

Jonathan Leffler
Jonathan Leffler

Reputation: 754110

Others have explained why file2 is empty (but, succinctly, it is because the redirection to file3 replaces the redirection to file2, so file2 is created or emptied but file3 gets the data from file1).

If you want the output in two files, use tee:

cat file1 | tee file2 > file3

There are other ways to do that, including:

tee < file1 file2 > file3

which has a certain pleasing symmetry to it. It also avoid the UUoC (Useless Use of cat) tag which the other is open to. However, if you had a variable number of input files (0 or standard input, or many – meaning more than one — or you needed to process command line arguments), then cat would still be correct. Note that tee can generate multiple files (so in some circumstances cat "$@" | tee file1 file2 file3 >/dev/null might make sense).

Upvotes: 4

AlvaroAV
AlvaroAV

Reputation: 10563

What's happening there is about how the standard input/output are managed.

You have cat file1>file2>file3 and what it is doing here is almost the same as

cat file1 > file3

Because file2 has it input redirected to the output

So, even if your file2 has some text in it and you execute

cat file1 >  file2 > file3

The content of file3 will still be the content of file1, why ?

CAT(1) User Commands CAT(1)

NAME cat - concatenate files and print on the standard output

DESCRIPTION Concatenate FILE(s), or standard input, to standard output.

Check the or (or standard input to standard output). You're redirecting the standard input from file2 directly to the standard output.

Let's supose this scenario:

  • file1 contains '123'
  • file2 contains '456
  • file3 doesn't exist

If you do cat file1 > file2 > file3 then the contents of the files will be

  • file1 contains '123'
  • file2 is empty
  • file3 contains '123'

file2 send to the output what file1 send to the input

Upvotes: 1

Chris Dodd
Chris Dodd

Reputation: 126253

The shell interprets file redirections from left to right before running the command. So when you enter

cat file1 > file2 > file3

it first does the redirection > file2 -- creating or emptying file2 and pointing stdout at it. Then it does > file 3, creating or emptying file3 and pointing stdout there. Finally it runs the command cat file1, which reads file1 and copies it to stdout. Since stdout is (now) pointing at file3, file3 ends up being a copy of that. Since nothing was written to stdout when it pointed at file2, file2 ends up empty.

Upvotes: 6

Michael Closson
Michael Closson

Reputation: 932

strace gives the answer.

open("file2", O_WRONLY|O_CREAT|O_TRUNC, 0666) = 3
dup2(3, 1)                        = 1
close(3)                          = 0
open("file3", O_WRONLY|O_CREAT|O_TRUNC, 0666) = 3
dup2(3, 1)                        = 1
close(3)                          = 0
execve("/bin/cat", ["cat", "file1"], [/* 38 vars */]) = 0

The second dup2() closes the file descriptor associated with file2. When cat runs, its stdout is file3.

Upvotes: 3

Related Questions