shell 如何在Makefile目标中使用Bash语法?

v1uwarro  于 2023-03-24  发布在  Shell
关注(0)|答案(7)|浏览(217)

我经常发现Bash语法非常有用,例如像diff <(sort file1) <(sort file2)中的进程替换。
是否可以在Makefile中使用这样的Bash命令?我正在考虑这样的东西:

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

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

798qvoo8

798qvoo81#

GNU Make documentation

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的顶部,您应该可以开始了。
顺便说一句:你也可以对一个目标这样做,至少对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中的任何位置,不必紧挨着目标之前。

vnzz0bqm

vnzz0bqm2#

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

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

当然,您可能无法重定向到变量$@,但是当我尝试这样做时,我得到了-bash: $@: ambiguous redirect作为错误消息,因此您可能希望在深入研究之前查看一下(尽管我使用的是bash 3.2.something,所以可能您的工作方式不同)。

kmpatx3s

kmpatx3s3#

一种有效的方法是将其放在目标的第一行:

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

nkkqxpd94#

如果可移植性很重要,你可能不想在Makefile中依赖于特定的shell。

flvlnr44

flvlnr445#

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

bash -c "ls -al"

而不是:

ls -al
js5cn81o

js5cn81o6#

有一种方法可以做到这一点,而不必显式地将SHELL变量设置为指向bash。如果您有许多makefile,这可能很有用,因为SHELL不会被后续的makefile继承或从环境中获取。您还需要确保编译您的代码的任何人都以这种方式配置他们的系统。
如果你运行sudo dpkg-reconfigure dash并对提示回答“no”,你的系统将不会使用dash作为默认shell。它将指向bash(至少在Ubuntu中是这样)。请注意,使用dash作为系统shell会更有效一些。

wnrlj8wa

wnrlj8wa7#

这不是对这个问题的直接回答,makeit是用bash语法有限的Makefile替换,在某些情况下它可能很有用 (我是作者)

  • 规则可以被定义为bash函数
  • 自动完成功能

基本思想是在脚本的末尾使用while循环:

while [ $# != 0 ]; do
  if [ "$(type -t $1)" == 'function' ]; then
    $1 
  else
    exit 1
  fi 
  shift
done

https://asciinema.org/a/435159

相关问题