views:

126

answers:

4

When the output of a command is redirected to a file, the output file is created or truncated by the shell before the command is executed, any idea what cat foo > foo does?

+1  A: 

The file is truncated first and then read, so this command would truncate the file.

When I tried to execute it I got this warning:

cat: test.txt: input file is output file

Mark Byers
What platform's `cat` do you have? `cat foo > foo` results in an empty `foo` file for me.
birryree
+3  A: 

On Fedora 13 this is what I see

cat foo > foo
cat: foo: input file is output file

If foo contained anything previously, it is gone.

Raghuram
A: 

Shell will truncate, cat apparently checks a named parm, but will not check against stdin as below and always succeeds:

$ uname -a
Linux bar 2.6.18-164.15.1.el5PAE #1 SMP Wed Mar 17 12:14:29 EDT 2010 i686 i686 i386 GNU/Linux
$ dd if=/dev/urandom of=foo bs=1024 count=4
4+0 records in
4+0 records out
4096 bytes (4.1 kB) copied, 0.00334456 seconds, 1.2 MB/s
$ od -c foo |head -2
0000000   U 371 003   z 224 334   z   K 236 221   k       <   c 256   !
0000020   %   % 256   V   \ 005   , 254   X 202 330 004 222   " 037 226
$ cat <foo >foo && od -c foo
0000000
Xepoch
Thanks for all of your replies. they were every helpful.
+5  A: 

In all cases, the file is truncated. That’s because redirection is handled by the shell, which opens the file for writing before invoking the command.

cat foo > foo

The shell truncates and opens foo for writing, sets stdout to the file, and then exec’s ["cat", "foo"].

GNU cat is smart and refuses to redirect a file to itself. It does this by checking the device/inode pair on the input and output file descriptors; you can read the wonderful low-level details in src/cat.c. It prints a message and quits.

BSD cat doesn’t have such a safety, but since the file has already been truncated, there is nothing to read, nothing to write, and it will halt.


You can spice things up a bit by appending instead of truncating.

echo hello > foo
cat foo >> foo

Now everything is the same except the shell opens the file for appending instead of truncating it.

GNU cat sees what you’re doing and stops; the file is untouched.

BSD cat goes into a loop and appends the file to itself until your disk fills up.

jleedev