如何检查Makefile中是否存在文件,以便删除它?

如何检查Makefile中是否存在文件,以便删除它?,makefile,Makefile,在我的Makefile的clean部分,我试图在永久删除之前检查该文件是否存在。我使用此代码,但收到错误 怎么了 if [ -a myApp ] then rm myApp fi 我收到了这个错误消息 if [ -a myApp ] /bin/sh: Syntax error: end of file unexpected (expecting "then") make: *** [clean] Error 2 缺少分号 if [ -a myApp ]; then

在我的
Makefile
的clean部分,我试图在永久删除之前检查该文件是否存在。我使用此代码,但收到错误

怎么了

 if [ -a myApp ]
 then
     rm myApp
 fi
我收到了这个错误消息

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

if [ -a myApp ];
then
  rm myApp
fi

但是,我假设您在删除之前检查是否存在,以防止出现错误消息。如果是这样,您可以使用“强制”删除的
rm-f myApp
,也就是说,如果文件不存在,则不会出错。

可能需要在行尾加一个反斜杠以继续(尽管这可能取决于make的版本):


或者只把它放在一行,因为
make
喜欢它:

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

看到这么多人为此使用shell脚本真是奇怪。我一直在寻找一种使用本地makefile语法的方法,因为我在任何目标之外编写它。您可以使用
通配符
功能检查文件是否存在:

 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 
更新:

我找到了一种真正适合我的方法:

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

问题是当您将命令拆分到多行上时。因此,您可以像上面一样在行的末尾使用
\
继续,也可以使用bash中的
&&
操作符在一行中获取所有内容

然后,您可以使用
test
命令测试文件是否存在,例如:

test -f myApp && echo File does exist
-f file
如果文件存在并且是常规文件,则为True

-s文件
如果文件存在且大小大于零,则为True

或不:

test -f myApp || echo File does not exist
test ! -f myApp && echo File does not exist
测试
相当于
[
命令

[ -f myApp ] && rm myApp   # remove myApp if it exists
它的工作原理与您最初的示例相同

有关更多语法,请参阅:
help[
help test

单行解决方案:

   [ -f ./myfile ] && echo exists
具有错误操作的单行解决方案:

   [ -f ./myfile ] && echo exists || echo not exists
我的
make clean
指令中使用的示例:

clean:
    @[ -f ./myfile ] && rm myfile || true
而且
保持干净
工作时不会出现错误信息

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)
执行结果:

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

第二个最上面的答案提到了
ifeq
,但是,它没有提到这些必须与目标的名称处于同一级别,例如,要下载当前不存在的文件,可以使用以下代码:

download:
ifeq (,$(wildcard ./glob.c))
    curl … -o glob.c
endif

# THIS DOES NOT WORK!
download:
    ifeq (,$(wildcard ./glob.c))
        curl … -o glob.c
    endif

像@mark wilkins使用\继续行和;在shell中终止行或像@kenorb将其更改为一行这样的答案都很好,可以解决这个问题

对于最初的问题有一个更简单的答案(正如@alexey polonsky所指出的)

rm -f myApp
这更简单、更快、更可靠,但要小心不要以斜杠和空变量结束

rm-f/$(myAppPath)#永远不要这样做

您可能最终会删除您的系统

test ! -f README.md || echo 'Support OpenSource!' >> README.md
如果README.md不存在,则不执行任何操作(并成功退出)。否则,请在末尾追加文本

如果使用
&&
而不是
|
,则当文件不存在时会生成错误:

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

[ -f $(PROGRAM) ] && cp -f $(PROGRAM) $(INSTALLDIR)
这个积极的例子奏效了,但我的ubuntu bash shell认为这是真的,并且在副本上出现了错误:

[ -f  ] && cp -f  /home/user/proto/../bin/
cp: missing destination file operand after '/home/user/proto/../bin/'
在得到这个错误后,我用谷歌搜索如何检查make中是否存在一个文件,这就是答案

ifneq ("$(wildcard $(PATH_TO_FILE))","")
    FILE_EXISTS = 1
else
    FILE_EXISTS = 0
endif
上面发布的这个解决方案效果最好。但请确保不要将路径\u到\u文件分配字符串化 例如:

一定是

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

与问题略有不同,但如果有一个变量包含要删除的文件列表,则可以执行以下操作

targets: filename1 filename2

clean_targets:
    @$(foreach file, $(targets), test -f $(file) && rm -v $(file) || echo No $(file);)

基本上,您可以循环使用targets变量定义的文件名,并使用“test”检查目标是否存在。如果存在,则删除该文件,如果不存在,则报告它不存在。最后一次检查(报告它不存在)是必需的,因为如果根本没有目标,则会引发错误

使用
test
命令检查文件是否存在,然后使用
rm
将其删除\

file命令的语法为-

test -f FILENAME && echo exists || echo not exists
删除文件的语法为-

rm -rf FILENAME
因此,现在我们需要一个命令,仅当文件存在时才删除该文件,因此我们将仅在test命令中使用OR
|

test -f FILENAME || rm -rf FILENAME
use可以通过在括号内使用and
&&
来使用多个命令
()


myApp是一个变量还是一个实际的文件名?myApp是myApplication的文件名,即生成过程中的文件名。如果您只是想避免在文件不存在时停止,
rm-rf myApp
可以是另一种选择。或者在命令前面加一个破折号(
-rm myApp
),使rm忽略错误(但它会打印一条难看的消息)。您的问题是make将规则中的每一行视为单独的命令,并将它们分别发送到shell。这就像单独运行'if[-a myApp]'。如果出现此错误,您需要一个将这些行合并为一行的解决方案(使用)或者每一行都独立于另一行。下面有几行。这正是我想要做的。非常感谢。这在生成文件中不起作用,因为if仍然分布在多行上-您需要将其放在一行上或使用\es。即使添加了\es,您仍然缺少一些分号ns.似乎不是Makefile语法?@holms是bash语法。通过转义新行,它允许将其作为单个bash命令处理。默认情况下,在
make
中,新行将是一个新的bash命令。除了在行尾有大量
\
的麻烦之外,主要的警告是每个命令都必须以bash中隐含的
结尾。正确的答案是@holms。无论是“\”还是通配符都不是专门用于此目的的。使用通配符的原因是为了代码清晰。此方法不仅可读性较差,而且更容易出现语法错误。提供的链接@holms不再起作用这是一个很好的答案,因为它
rm -rf FILENAME
test -f FILENAME || rm -rf FILENAME
test -f FILENAME || (rm -rf FILENAME && echo "file deleted as it exists")