Say I have the following files:
buggy_program:
#!/bin/sh
echo \"wops, some bug made me exit with failure\"
exit 1
Makefile:
<
Here's a possible solution that doesn't require bash. Imagine you have two programs thisworks
and thisfails
that fail or work fine, respectively. Then the following will only leave you with work.gz
, deleting fail.gz
, ie. create the gzipped make target if and only if the program executed correctly:
all: fail.gz work.gz
work.gz:
( thisworks && touch $@.ok ) | gzip -c -9 >$@
rm $@.ok || rm $@
fail.gz:
( thisfails && touch $@.ok ) | gzip -c -9 >$@
rm $@.ok || rm $@
Explanation:
In the first line of the work.gz
rule, thisworks
will exit with success, and a file work.gz.ok
will be created, and all stdout goes through gzip into work.gz
. Then in the second line, because work.gz.ok
exists, the first rm
command also exits with success – and since ||
is short-circuiting, the second rm
does not get run and so work.gz
is not deleted.
OTOH, in the first line of the fail.gz
rule, thisfails
will exit with failure, and fail.gz.ok
will not be created. All stdout still goes through gzip into fail.gz
. Then in the second line, because fail.gz.ok
does not exist, the first rm
command exits with failure, so ||
tries the second rm
command which deletes the fail.gz
file.
To easily check that this works as it should, simply replace thisworks
and thisfails
with the commands true
and false
, respectively, put it in a Makefile and type make
.
(Thanks to the kind people in #autotools for helping me with this.)