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

在我的 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
263865 次浏览

少了一个分号

if [ -a myApp ];
then
rm myApp
fi

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

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

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

或者就像 make喜欢的那样,把它放在一行上:

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

看到这么多人使用 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

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

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

test -f myApp && echo File does exist

如果文件存在并且是普通文件,则为真。

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

或没有:

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

解决办法只有一条:

   [ -f ./myfile ] && echo exists

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

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

在我的 make clean指令中使用的示例:

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

而且 make clean没有错误消息!

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,但是它没有提到这个 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

像@mark-wilkins 用来继续行和; 在 shell 中终止行或像@kenorb 用来将这行改为一行的那些答案都很好,并且可以解决这个问题。

对于最初的问题,有一个更简单的答案(@alexey-polonsky 指出)。将-f 标志用于 rm,这样它就不会触发错误

rm -f myApp

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

永远不要这样做

你可能会删除你的系统。

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 调用了这个 TRUE 并在副本上打破了:

[ -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

上面提到的这个解决方案效果最好,但是请确保不要对 PATH _ TO _ FILE 赋值进行限定 例如:

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

一定是

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);)

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

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

File 命令的语法是-

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

删除文件的语法是-

rm -rf FILENAME

所以现在我们只需要一个命令来删除存在的文件,所以我们将只使用 OR ||和 test 命令

test -f FILENAME || rm -rf FILENAME

Use 可以通过 using 和 &&在括号 ()中使用多个命令

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

我想要指挥上面的人,但是名声:)

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

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


.ONESHELL: all-in-one-shell

这就避免了尝试想出创造性的俏皮话或反斜杠的一切。

我们还可以利用 GNU Coreutils 的 test内置函数(手动操作) ,这意味着我们可以像下面这样检查文件的存在:

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

或者更巧妙地说,像这样:

check_exist:
[ -f file ] && echo yes || echo no