我经常发现Bash语法非常有用,例如,像diff <(sort file1) <(sort file2)这样的进程替换。

是否可以在Makefile中使用这样的Bash命令?我的想法是这样的:

file-differences:
    diff <(sort file1) <(sort file2) > $@

在我的GNU Make 3.80中,这将给出一个错误,因为它使用shell而不是bash来执行命令。


当前回答

你可以直接在Makefile中调用bash,而不是使用默认shell:

bash -c "ls -al"

而不是:

ls -al

其他回答

还有一种方法是把它放在你的目标的第一行:

your-target: $(eval SHELL:=/bin/bash)
    @echo "here shell is $$0"

你可以直接调用bash,使用-c标志:

bash -c "diff <(sort file1) <(sort file2) > $@"

当然,您可能无法重定向到变量$@,但是当我尝试这样做时,我得到了-bash: $@:模棱两可的重定向作为错误消息,所以您可能希望在深入了解这个问题之前研究一下(尽管我使用的是bash 3.2。也许你的工作方式不同)。

有一种方法可以做到这一点,而无需显式地将SHELL变量设置为指向bash。如果您有许多makefile文件,这可能很有用,因为SHELL不会被后续的makefile文件继承或从环境中获取。您还需要确保任何编译您代码的人都以这种方式配置他们的系统。

如果运行sudo dpkg-reconfigure dash并对提示符回答“no”,系统将不会使用dash作为默认shell。然后它将指向bash(至少在Ubuntu中)。注意,使用破折号作为你的系统外壳是更有效的。

在GNU Make文档中,

5.3.2 Choosing the Shell
------------------------

The program used as the shell is taken from the variable `SHELL'.  If
this variable is not set in your makefile, the program `/bin/sh' is
used as the shell.

因此,将SHELL:= /bin/bash放在makefile的顶部,您就可以开始了。

BTW:你也可以为一个目标这样做,至少在GNU Make中。每个目标都可以有自己的变量赋值,如下所示:

all: a b

a:
    @echo "a is $$0"

b: SHELL:=/bin/bash   # HERE: this is setting the shell for b only
b:
    @echo "b is $$0"

这将打印:

a is /bin/sh
b is /bin/bash

更多细节请参见文档中的“特定于目标的变量值”。这一行可以在Makefile中的任何地方,它不必紧挨着目标。

你可以直接在Makefile中调用bash,而不是使用默认shell:

bash -c "ls -al"

而不是:

ls -al