在我的 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
少了一个分号
if [ -a myApp ]; then rm myApp fi
但是,我假设您是在删除之前检查是否存在以防止错误消息。如果是这样的话,你可以使用 rm -f myApp,它“强制”删除,也就是说,如果文件不存在,不会出错。
rm -f myApp
它可能需要在行尾加一个反斜杠以便继续(尽管这可能取决于 make 的版本) :
if [ -a myApp ] ; \ then \ rm myApp ; \ fi;
或者就像 make喜欢的那样,把它放在一行上:
make
if [ -a myApp ]; then rm myApp; fi;
看到这么多人使用 shell 脚本实现这一点很奇怪。我正在寻找一种使用本机 makefile 语法的方法,因为我是在任何目标之外编写这个代码的。您可以使用 wildcard函数检查文件是否存在:
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
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。
help [
help test
解决办法只有一条:
[ -f ./myfile ] && echo exists
带有错误操作的一行解决方案:
[ -f ./myfile ] && echo exists || echo not exists
在我的 make clean指令中使用的示例:
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 中与目标名称处于相同的缩进级别,例如,只有当目标名称不存在时才下载文件,可以使用以下代码:
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 指出)。将-f 标志用于 rm,这样它就不会触发错误
这样更简单,更快,更可靠。只是要小心不要以一个斜杠和一个空变量结束
永远不要这样做
你可能会删除你的系统。
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,这是答案..。
上面提到的这个解决方案效果最好,但是请确保不要对 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删除文件
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