In the normal case, this would output file.out
$ program1 | program2 | program3 > file.out
But what happens if program1
fails? What happens is that the rest of the chain still fires and the file is created
$ false | echo worked > file.out
$ cat file.out
worked
I don't want the file to appear.
There is another SO article about this that suggests adding an OR clause, like so:
$ false | echo worked > file.out || rm file.out
ls file.out
file.out
This doesn't work. The second command fires and counts as a success.
That same SO article also suggests using a double ampersand, like so:
$ program1 && program2 && program2 > file.out
That doesn't work entirely. In my case program2 is expecting output from the stdout, so this chain ends up hanging because the chain is not stopping. You can see how this works with a trivial example:
$ echo something > stuff.txt
$ cat stuff.txt && false > file.out
something
$ cat file.out
It's not redirecting the output.
But, even worse, when things are happy, it doesn't work either.
$ echo something > stuff.txt
$ cat stuff.txt && true > file.out
something
$ cat file.out
In this case, file.out is created and it's blank. Uh-Oh.
I accepted an answer below. Calling set -o pipefail
was the tip that I needed. In my real situation, I'm using a Makefile. To adapt this to work in a Makefile, I added this to the top of the file
SHELL=/bin/bash
And then to my target:
target:
@set -o pipefail; program1 | program2 | program3 > $@