在GNU Make 4中使用"bash -e"作为shell时,rm -f无法丢失文件

Joh*_*vin 1 bash makefile gnu-make

我有一个Makefile,如下所示:

.ONESHELL:
SHELL = /bin/bash
.SHELLFLAGS = -e

clean:
    rm -f foo

.PHONY: clean
Run Code Online (Sandbox Code Playgroud)

foo不存在.当我在Debian上运行它时,GNU Make 4.1我得到了这个错误:

rm -f foo
/bin/bash: rm -f foo: No such file or directory
Makefile:6: recipe for target 'clean' failed
make: *** [clean] Error 1
Run Code Online (Sandbox Code Playgroud)

当我在macOS上运行它时,GNU Make 3.81它按预期工作.如果我写-rm -f而不是,那没有区别rm -f.

为什么我会收到错误?bash -e -c "rm -f foo" ; echo $?在shell 0上运行打印在两个系统上.

我错过了什么吗?

ilk*_*chu 6

必须非常仔细地阅读错误消息:

/bin/bash: rm -f foo: No such file or directory
Run Code Online (Sandbox Code Playgroud)

这不是rm说它无法找到foo的消息,它是来自Bash的消息,告诉它找不到文件rm -f foo(文件名中有空格).

使用.SHELLFLAGS = -e,shell获得与命令行相同的内容:

bash -e "rm -f foo"
Run Code Online (Sandbox Code Playgroud)

所以它查找一个文件rm -f foo来读取命令.您需要显式添加-c标志以告诉它将参数本身作为命令,即.SHELLFLAGS = -ec导致

bash -ec "rm -f foo"
Run Code Online (Sandbox Code Playgroud)

毫不奇怪,默认值.SHELLFLAGS包含-c:

传递给shell的参数取自变量.SHELLFLAGS.默认值通常.SHELLFLAGS-c,或-ec符合POSIX模式.


Mad*_*ist 5

这是一个无效的设置.SHELLFLAGS。这将导致被调用:

/bin/sh -e 'rm -f foo'
Run Code Online (Sandbox Code Playgroud)

这不是有效的命令行;它告诉 shell 运行一个名为字面意思的程序,rm -f foo这显然是错误的。您必须确保-c也添加了该选项,并且由于许多 shell 只允许在第一个参数中使用选项,因此您需要:

.SHELLFLAGS = -ec
Run Code Online (Sandbox Code Playgroud)

这记录在GNU make 手册中。

它在较旧的 GNU make 3.81 中“工作”的原因是该版本.SHELLFLAGS根本不支持该选项,因此该行被忽略。