Makefile - make 找到一个文件而 shell 没有

Makefile - make finds a file whilst shell does not

我写了一段 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: 未找到
找到 main.o factorial.o

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

感谢您花时间阅读这个问题。这是我第一次来这里,所以如果我做错了什么,请告诉我

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

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

编写 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。明确列出您要使用的文件。