9

I am trying to run a command in bash where I have a command 1 which accepts a large amount content through stdin and then outputs that content to a file.txt, however, command 1 generates a stream of content and apparently file.txt gets created as soon as command 1 starts and then gets updated once command 1 finishes with the correct output.

echo 'a lot of content' | command 1 > file.txt

The problem is that I only want to create or touch file.txt once command 1 is completely finished.

Is there any way to achieve that?

Edit:

Use-case: I am using a web development server that gets refreshed every time a file changes, so I am doing some pre-processing before really updating the file.

The problem with the above command is that if the file is updated or create with empty content the server refreshes instantly, having an empty page, so I really wanted to wait for the post processing to finish (let's say it takes about 4 seconds) and only then touch file.txt so it is correctly rendered on the page.

So there's only one command I need to run here, which is command 1 and then, after file.txt is updated, my web development server will refresh automatically.

zanona
  • 311

2 Answers2

16

Use sponge from GNU moreutils:

echo 'a lot of content' | command 1 | sponge file.txt

Or use a temporary file.

heemayl
  • 56,300
15

The simplest solution is probably sponge as @heemayl suggested. Alternatively, you could do something like this:

command > tmpfile && mv tmpfile watched_file

This will cause command to save its output in tmpfile, which will only be renamed to watched_file (the file your server is set up to watch) once the command has exited and only if it has exited successfully. To also rename it on failure, use:

command > tmpfile; mv tmpfile watched_file
terdon
  • 242,166
  • Thank you. I prefer the tmpfile method since I was looking for something that could work without dependencies. – zanona Apr 03 '16 at 12:57
  • If the command fail, an unused tmpfile will be created. To prevent that we can do something like this { command >tmpfile && mv tmpfile watched_file; } || rm tmpfile – Navid Ht Apr 05 '16 at 19:27