cat, pipes, and filters

Jonathan I Kamens jik at cats.ucsc.edu
Sat Jun 1 05:19:33 AEST 1991


In article <1991May31.165446.1530 at progress.com>, root at progress.COM (Root of all Evil) writes:
|>    cat $FILE | sed s/"$ENTRY"/"$NEWENTRY"/ > $FILE
|> 
|>    cat $FILE | sed s/"$ENTRY"/"$NEWENTRY"/ | cat > $FILE

In this case, you're using shell redirection to output to the file.  Shell
redirection takes place before any of the commands on the command line
actually get run.  Therefore, the shell opens $FILE and truncates it in
preparation for sending output to it *before* the "cat" at the beginning of
the pipeline opens it in order to read it.

|>    cat $FILE | sed s/"$ENTRY"/"$NEWENTRY"/ | tee $FILE 1>/dev/null

In this case, cat gets started and opens the file in order to read it, and
*then* tee gets started, sees that it's supposed to send output to $FILE, and
opens the file and truncates it in preparation for sending output to it.  Once
cat has opened the file for read, it gets to read it, because the file that
tee is sending output to is (in effect) a "different file" from the kernel's
point of view.

|> So now my script works but I don't really understand why.  I've tested
|> this on SunOs 4.1 and Interactive SysV 2.2, no difference.  Is there
|> something simple about pipes or I/O redirection that I'm not grasping?
|> Or is this a feature of cat?  

Quoting from the man page cat(1):

NOTES
     Beware of `cat a b > a' and `cat a b > b', which destroy the
     input files before reading them.



More information about the Comp.unix.shell mailing list