[makefile] How do I check if file exists in Makefile so I can delete it?

In the clean section of my Makefile I am trying to check if the file exists before deleting permanently. I use this code but I receive errors.

What's wrong with it?

 if [ -a myApp ]
 then
     rm myApp
 fi

I get this error message

 if [ -a myApp ]
 /bin/sh: Syntax error: end of file unexpected (expecting "then")
 make: *** [clean] Error 2

This question is related to makefile

The answer is


test ! -f README.md || echo 'Support OpenSource!' >> README.md

"If README.md does not exist, do nothing (and exit successfully). Otherwise, append text to the end."

If you use && instead of || then you generate an error when the file doesn't exist:

Makefile:42: recipe for target 'dostuff' failed
make: *** [dostuff] Error 1

Or just put it on one line, as make likes it:

if [ -a myApp ]; then rm myApp; fi;

The problem is when you split your command over multiple lines. So, you can either use the \ at the end of lines for continuation as above or you can get everything on one line with the && operator in bash.

Then you can use a test command to test if the file does exist, e.g.:

test -f myApp && echo File does exist

-f file True if file exists and is a regular file.

-s file True if file exists and has a size greater than zero.

or does not:

test -f myApp || echo File does not exist
test ! -f myApp && echo File does not exist

The test is equivalent to [ command.

[ -f myApp ] && rm myApp   # remove myApp if it exists

and it would work as in your original example.

See: help [ or help test for further syntax.


The answers like the one from @mark-wilkins using \ to continue lines and ; to terminate them in the shell or like the ones from @kenorb changing this to one line are good and will fix this problem.

there's a simpler answer to the original problem (as @alexey-polonsky pointed out). Use the -f flag to rm so that it won't trigger an error

rm -f myApp

this is simpler, faster and more reliable. Just be careful not to end up with a slash and an empty variable

rm -f /$(myAppPath) #NEVER DO THIS

you might end up deleting your system.


I was trying:

[ -f $(PROGRAM) ] && cp -f $(PROGRAM) $(INSTALLDIR)

And the positive case worked but my ubuntu bash shell calls this TRUE and breaks on the copy:

[ -f  ] && cp -f  /home/user/proto/../bin/
cp: missing destination file operand after '/home/user/proto/../bin/'

After getting this error, I google how to check if a file exists in make, and this is the answer...


One line solution:

   [ -f ./myfile ] && echo exists

One line solution with error action:

   [ -f ./myfile ] && echo exists || echo not exists

Example used in my make clean directives:

clean:
    @[ -f ./myfile ] && rm myfile || true

And make clean works without error messages!


It's strange to see so many people using shell scripting for this. I was looking for a way to use native makefile syntax, because I'm writing this outside of any target. You can use the wildcard function to check if file exists:

 ifeq ($(UNAME),Darwin)
     SHELL := /opt/local/bin/bash
     OS_X  := true
 else ifneq (,$(wildcard /etc/redhat-release))
     OS_RHEL := true
 else
     OS_DEB  := true
     SHELL := /bin/bash
 endif 

Update:

I found a way which is really working for me:

ifneq ("$(wildcard $(PATH_TO_FILE))","")
    FILE_EXISTS = 1
else
    FILE_EXISTS = 0
endif

It may need a backslash on the end of the line for continuation (although perhaps that depends on the version of make):

if [ -a myApp ] ; \
then \
     rm myApp ; \
fi;

FILE1 = /usr/bin/perl
FILE2 = /nofile

ifeq ($(shell test -e $(FILE1) && echo -n yes),yes)
    RESULT1=$(FILE1) exists.
else
    RESULT1=$(FILE1) does not exist.
endif

ifeq ($(shell test -e $(FILE2) && echo -n yes),yes)
    RESULT2=$(FILE2) exists.
else
    RESULT2=$(FILE2) does not exist.
endif

all:
    @echo $(RESULT1)
    @echo $(RESULT2)

execution results:

bash> make
/usr/bin/perl exists.
/nofile does not exist.

ifneq ("$(wildcard $(PATH_TO_FILE))","")
    FILE_EXISTS = 1
else
    FILE_EXISTS = 0
endif

This solution posted above works best. But make sure that you do not stringify the PATH_TO_FILE assignment E.g.,

PATH_TO_FILE = "/usr/local/lib/libhl++.a" # WILL NOT WORK

It must be

PATH_TO_FILE = /usr/local/lib/libhl++.a

Missing a semicolon

if [ -a myApp ];
then
  rm myApp
fi

However, I assume you are checking for existence before deletion to prevent an error message. If so, you can just use rm -f myApp which "forces" delete, i.e. doesn't error out if the file didn't exist.