I am trying to instruct GNU Make 3.81 to not stop if a command fails (so I prefix the command with -) but I also want to check the exit status on the next command and print a more informative message. However my Makefile below fails:

$ cat Makefile 
    ([ $$? -eq 0 ] && echo "success!") || echo "failure!"
$ make
make: [all] Error 1 (ignored)
([ $? -eq 0 ] && echo "success!") || echo "failure!"

Why does the Makefile above echo "success!" instead of "failure!" ?


Following and expanding on the accepted answer, below is how it should be written:

    @-/bin/false && ([ $$? -eq 0 ] && echo "success!") || echo "failure!"                                                                                                                                                                 
    @-/bin/true && ([ $$? -eq 0 ] && echo "success!") || echo "failure!"     
  • 3
    You might want to investigate the .ONESHELL: directive. Commented Feb 10, 2015 at 14:54
  • 1
    .ONESHELL will run all receipt block in one shell which has effect: if first command fails, next ones will be executed without problems. To prevent this .SHELLFLAGS = -ec should be used. But in this case you can not use - prefix more (for personal command of the receipt) because the make will write that error is ignored but still will fail all the block. So, || : is one the solution to ignore command. But it's not cross-platform (Windows has not || : or || true)
    – RandomB
    Commented Jun 4, 2019 at 11:33
  • --keep-going should continue to the next line in the file with the exit code intact Commented Jan 26, 2023 at 20:31

4 Answers 4


Each update command in a Makefile rule is executed in a separate shell. So $? does not contain the exit status of the previous failed command, it contains whatever the default value is for $? in a new shell. That's why your [ $? -eq 0 ] test always succeeds.


You don't need the test of $? since && works if $? is zero and || is proceed in case of a non-zero return value.

And you don't need the minus since at the return value to make is taken from the last proceed program call of the line. So this works fine


      @/bin/false && echo "success!" || echo "failure!" 


      @/bin/true && echo "success!" || echo "failure!"

The opposite happens: If you wanna do your own message and want to break the make process anyway with a non-zero value, you need to write something like this:


      @/bin/false && echo "success!" || { echo "failure!"; exit 1; }

From the GNU make documentation:

When errors are to be ignored, because of either a ‘-’ or the ‘-i’ flag, make treats an error return just like success, except that it prints out a message that tells you the status code the shell exited with, and says that the error has been ignored.

To utilize make's exit status in a case like this, execute make from a script:

([ $? -eq 0 ] && echo "success!") || echo "failure!"

And have your Makefile contain:


Here is how I ended up doing it:

.PHONY: test-cleanup
    $(eval CLEANUP = echo "Some cleanup procedure")
    @/bin/true && touch _testok || $(CLEANUP) ;\
    if [ -f "_testok" ]; then \
        rm -f _testok ;\
        echo "What a success!" ;\
    else \
        echo "Failure :-(" ;\
        exit 1 ;\

Which prints:

What a success!

If you change /bin/true to /bin/false then you get the following output:

Some cleanup procedure
Failure :-(
make: *** [Makefile:4: test-cleanup] Error 1

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .