5

In a particular directory, I made a file named "fileName" and add contents to it. When I typed cat fileName, it's content are printed on the terminal. Now I used the following command:

cat fileName>fileName

No error was shown. Now when I try to see contents of file using,

cat fileName

nothing was shown in the terminal and file is empty (when I checked it). What is the reason for this?

hyde
  • 60,639
  • 21
  • 115
  • 176
Ugnes
  • 709
  • 1
  • 9
  • 23
  • 7
    Possible duplicate of [How can I use a file in a command and redirect output to the same file without truncating it?](https://stackoverflow.com/questions/6696842/how-can-i-use-a-file-in-a-command-and-redirect-output-to-the-same-file-without-t) – Nick Roz Feb 15 '19 at 19:09

3 Answers3

11

> i.e. redirection to the same file will create/truncate the file before cat command is invoked as it has a higher precedence. You could avoid the same by using intermediate file and then from intermediate to actual file or you could use tee like:

cat fileName | tee fileName
SMA
  • 36,381
  • 8
  • 49
  • 73
  • 1
    May i know the reason for downvote @downvoter? Please comment when you downvote a answer so it would help others as well and ofcourse me! – SMA Sep 11 '16 at 17:17
  • For some reason that doesn't work if the stream goes through another sed command: https://gist.github.com/nikolay-popov/7f6668706985927ddaf99bc9a380e270 – Nikolay Popov Sep 13 '18 at 15:47
  • Answer is correct but example doesn't seem to work, just several consequent calls of `echo 'hello' | cat - text | tee text` occasionally rewrites file `text`; by some reason this command is not executed instantly – Nick Roz Feb 15 '19 at 19:21
3

To clarify on SMA's answer, the file is truncated because redirection is handled by the shell, which opens the file for writing before invoking the command. when you run cat file > file,the shell truncates and opens the file for writing, sets stdout to the file, and then execute ["cat", "file"]. So you will have to use some other command for the task like tee

Nithin
  • 5,470
  • 37
  • 44
3

The answers given here are wrong. You will have a problem with truncating regardless of using the redirect or pipeline, although it may APPEAR to work sometimes, depending on size of file or length of your pipeline. It is a race condition, as the reader may have a chance to read some or all of the file before the writer starts, but the point of the pipeline is to run all these at the same time so they will be starting at the same time and the first thing tee executable will do is open the output file (and truncate it in the process). The only way you will not have a problem in this scenario is if the end of the pipeline would load the entirety of the output into memory and only write it to file on shutdown. It is unlikely to happen and defeats the point of having a pipeline.

Proper solution for making this reliable is to just write to a temp file and then rename the temp file back to original filename:

TMP="$(mktemp fileName.XXXXXXXX)"
cat fileName | grep something | tee "${TMP}"
mv "${TMP}" fileName
  • see also https://stackoverflow.com/questions/6696842/how-can-i-use-a-file-in-a-command-and-redirect-output-to-the-same-file-without-t – elonderin Jul 25 '23 at 09:23