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

问题描述 投票:0回答:16

在我的

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

有什么问题吗?

 if [ -a myApp ]
 then
     rm myApp
 fi

我收到此错误消息

 if [ -a myApp ]
 /bin/sh: Syntax error: end of file unexpected (expecting "then")
 make: *** [clean] Error 2
makefile
16个回答
258
投票

看到这么多人为此使用 shell 脚本,这很奇怪。我一直在寻找一种使用本机 makefile 语法的方法,因为我是在任何目标之外编写此语法的。您可以使用

wildcard
函数检查文件是否存在:

 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

108
投票

第二个最佳答案提到了

ifeq
,但是,它没有提到这个
ifeq
必须在makefile中与目标名称具有相同的缩进级别,例如,仅在不存在的情况下才下载文件目前存在,可以使用以下代码:

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

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

81
投票

问题是当您将命令拆分为多行时。因此,您可以像上面一样在行尾使用

\
来继续,也可以在 bash 中使用
&&
运算符将所有内容放在一行上。

然后您可以使用

test
命令来测试文件是否存在,例如:

test -f myApp && echo File does exist

-f file
如果文件存在并且是常规文件,则为真。

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

或不:

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

test
相当于
[
命令。

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

它会像你原来的例子一样工作。

请参阅:

help [
help test
了解更多语法。


55
投票

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

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

38
投票

或者只是把它放在一行上,就像

make
喜欢的那样:

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

25
投票

一条线解决方案:

   [ -f ./myfile ] && echo exists

带有错误操作的一行解决方案:

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

我的

make clean
指令中使用的示例:

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

并且

make clean
可以正常工作,不会出现错误消息!


17
投票
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.

14
投票

少了一个分号

if [ -a myApp ];
then
  rm myApp
fi

但是,我假设您在删除之前检查是否存在,以防止出现错误消息。如果是这样,您可以使用

rm -f myApp
来“强制”删除,即如果文件不存在,则不会出错。


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

上面发布的这个解决方案效果最好。但请确保您没有将 PATH_TO_FILE 分配字符串化 例如,

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

一定是

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

1
投票

答案类似于 @mark-wilkins 的答案,使用 \ 来继续行,并且 ;在 shell 中终止它们或者像 @kenorb 中的那样将其更改为一行都很好,并且可以解决此问题。

对于原始问题有一个更简单的答案(正如@alexey-polonsky 指出的那样)。使用 -f 标志来 rm 这样就不会触发错误

rm -f myApp

这更简单、更快、更可靠。只是要小心不要以斜杠和空变量结束

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

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


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

“如果 README.md 不存在,则不执行任何操作(并成功退出)。否则,将文本附加到末尾。”

如果您使用

&&
而不是
||
那么当文件不存在时会生成错误:

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

1
投票

使用

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

文件命令的语法是 -

test -f FILENAME && echo exists || echo not exists

删除文件的语法是-

rm -rf FILENAME

所以现在我们需要一个命令来删除文件(仅当文件存在时),因此我们将仅将 OR

||
与测试命令一起使用

test -f FILENAME || rm -rf FILENAME

use 可以通过在括号内使用 和

&&
来使用多个命令
()

test -f FILENAME || (rm -rf FILENAME && echo "file deleted as it exists")

0
投票

我正在尝试:

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

正面案例有效,但我的 ubuntu bash shell 称此为 TRUE 并在副本上中断:

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

收到此错误后,我谷歌如何检查 make 中是否存在文件,这就是答案...


0
投票

与问题略有不同,但如果您有一个包含要删除的文件列表的变量,您可以这样做

targets: filename1 filename2

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

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


0
投票

我想指挥上面,但是声望:)

您可以通过添加 .ONESHELL: 指令在 gnu make 目标中使用多行命令:

all-in-one-shell:
    if [ -a MyApp ] ; then
        echo "here"
    fi

.ONESHELL: all-in-one-shell

这消除了尝试想出有创意的俏皮话或反斜杠的一切。


0
投票

我们还可以利用 GNU Coreutils 的

test
内置功能(manual),这意味着我们可以像这样检查文件是否存在:

check_exist:
    test -f file && echo yes || echo no 

或更简洁,像这样:

check_exist:
    [ -f file ] && echo yes || echo no 
© www.soinside.com 2019 - 2024. All rights reserved.