1

My Makefile is very simple:

all:
      [ -f MyFile ] && echo "MyFile exists"

Of course the recipe line begins with tab. If the file MyFile really exists, everything is ok. But if this file is not in the current directory I get:

Makefile:2: recipe for target 'all' failed make: *** [all] Error 1

I can get rid of this error using the if statement instead:

all:
      if [ -f MyFile ]; then echo "MyFile exists"; fi

Both statements work fine in sh and bash outside make. It is unclear for me what is the reason of the make error when the conditional operator is used. An ideas what is going on?

makopec
  • 13
  • The line you are talking about is called command line in the standard and in the documentation of all make implementations except gmake. – schily Mar 17 '20 at 13:11

1 Answers1

2
[ -f MyFile ] && echo "MyFile exists"

exits with a non-zero status code if MyFile doesn’t exist, whereas

if [ -f MyFile ]; then echo "MyFile exists"; fi

exits with a successful (zero) status code unless MyFile exists and echo fails with a write error.

Make relies on status codes to determine whether commands failed, and it stops execution by default when any command fails. You can disable this for individual command lines by prefixing them with -, or overall by running make -i or by specifying the special .IGNORE target. Thus

-[ -f MyFile ] && echo "MyFile exists"

would both allow Make to continue, but would still cause it to print a message if MyFile doesn’t exist:

make: [Makefile:14: test] Error 1 (ignored)

The || true pattern would also work in this specific case, but it would ignore errors in echo. if condition; then command; fi won’t cause Make to stop if condition is false, but will take command’s errors into account, whereas condition && command || true will ignore all errors.

Stephen Kitt
  • 434,908
  • @pizdelect good point; I mentioned the specific || true pattern instead of the more general || cmd2 pattern, but that does result in errors being ignored. – Stephen Kitt Mar 17 '20 at 13:40