首页 > 解决方案 > Makefile - make 找到一个文件,而 shell 没有

问题描述

我编写了一个 Makefile 片段,用于在执行rm之前检查文件是否存在。

clean:
echo "Attempt to remove $(exec) file"
if test -f "${exec}" ; then \
echo "Removing file ${exec}" ; \
rm ${exec} ; \
else \
echo "No ${exec} file to remove" ; \
fi

if "$(wildcard *.o)" = "" ; then \
echo "No files found" ; \
else \
echo " Found $(wildcard *.o) " ; \
fi

首先if语句工作正常
尝试删除 hello 文件
没有要删除的 hello 文件

而第二个产生这个:

/bin/sh: 1: main.o factorial.o: not found
main.o factorial.o

我的问题是:为什么make recipe会产生有效的输出(这些文件确实存在)而shell没有?为什么shell甚至试图找到它们?

感谢您花时间阅读这个问题。这是我的第一个,所以如果我做了不恰当的事情,请告诉我

标签: linuxmakefilegnu-make

解决方案


if main.o与 非常不同if test -f main.o。前者尝试运行命令main.o,而后者运行命令testif "main.o factorial.o"类似,因为它尝试运行一个名为的命令main.o factorial.o,shell 正确地抱怨它找不到。您的 PATH中不太可能有一个名为main.o factorial.o(即名称中带有空格的单个文件)的文件。

但不要这样做。在取消链接之前检查文件是否存在绝对没有意义。有一个固有的竞争条件。只需尝试删除该文件,并处理如果该文件不存在可能发生的错误。

它更容易编写rm $(wildcard *.o),只需rm为不存在的文件发出错误消息。或rm -f $(wildcard *.o)抑制错误。如果您真的坚持遍历文件并检查,您可以执行以下操作:

for f in $(wildcard *.o); do \
    if ! test -f "$$f"; then echo "$$f" does not exist; \
    else rm "$$f"; fi

但这真的不值得。此外,这似乎毫无意义,因为wildcard它只会扩展到存在的文件。(但请注意,这表现出相同的竞争条件:通配符可能会扩展为文件列表,但可能会在通配符扩展和rm运行之间创建新文件。)不要这样使用wildcard。明确列出您要使用的文件。


推荐阅读