1

I am learning bash and am not able to understand what is going wrong with the output redirection in the following example:

I have a file called myfile.txt with the following content.

Practice makes Perfect

I am going to use tr command to replace P with p:

cat myfile.txt | tr P p

This does what I want, now I am going to put the result back into the original file:

cat myfile.txt | tr P p > myfile.txt

But after executing the above command myfile.txt is empty... why is this happening?


Update:

If I send the output to a different file, then it works as expected:

cat myfile.txt | tr P p > anotherfile.txt
  • 1
    You should not use the same file for input and output. What you are doing is open a file for reading, and then create a new file with the same name for writing the result into it. Try also this cat myfile.txt | tr P p >> myfile.txt. Appending to a file does not create a new file, and in that case the content is not deleted. Well, it gets repeated with tr P p altered content. – nobody Aug 22 '19 at 05:33
  • 2
    It's because the shell opens myfile.txt for writing and truncates it first - see for example Warning regarding ‘>’ – steeldriver Aug 22 '19 at 05:42
  • https://askubuntu.com/questions/20414/find-and-replace-text-within-a-file-using-commands –  Aug 25 '19 at 11:23

3 Answers3

2

Bash (and other POSIX-compliant shells) follow two rules that explain this behavior:

  • Redirection happens before commands run.

  • If a file exists, it is truncated (emptied) when redirection goes to the file as in > myfile.txt.

So because there is > redirection the contents of the myinput.txt get discarded and cat prints nothing, cat exits and closes the pipe and tr closes the file without writing anything to it. Order in which commands start is not particularly important ( and it is not guaranteed, see Gille's answer here). But what is important is that redirection occurring before commands starting; that is each command's standard streams are prepared, and that's what causes empty file in the end.

But it is possible to edit the same file tools like sponge, just not in this particular case.

See also:

Sergiy Kolodyazhnyy
  • 105,154
  • 20
  • 279
  • 497
0

Use: sort -o instead of redirection. I n such a way you will be able to write to the same file.

cat myfile.txt | tr P p | sort -o myfile.txt
Josef Klimuk
  • 1,596
  • I'd suggest sponge command instead. sort will do sorting which will change order of lines. I'd also be careful with race condition. In this case because of 3 pipes, sort can read stdin into buffer without interfering with cat, but if it's a large file, data may be lost partially. About sponge: https://unix.stackexchange.com/a/207921/85039 – Sergiy Kolodyazhnyy Jan 02 '20 at 08:03
-1

In my opinion cat is not used in the correct intention. Normally cat is used to combine files, but often also misused to just use display simple files.

In your case I would use the tr command in the following way:

tr P p < myInput.txt > myOutput.txt