【问题标题】:How can I use Bash syntax in Makefile targets?如何在 Makefile 目标中使用 Bash 语法?
【发布时间】:2010-10-10 00:15:15
【问题描述】:

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

是否可以在 Makefile 中使用此类 Bash 命令?我正在考虑这样的事情:

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

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

【问题讨论】:

  • 这正是我的问题,我花了至少一个小时才找到这个问题!我在这里留下我的错误信息,以便未来的读者可以找到它:/bin/sh: -c: line 0: syntax error near unexpected token ('`

标签: bash shell makefile


【解决方案1】:

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

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

当然,您可能无法重定向到变量 $@,但是当我尝试这样做时,我收到了 -bash: $@: ambiguous redirect 作为错误消息,因此您可能需要在深入了解之前先查看一下这个(虽然我使用的是 bash 3.2.something,所以也许你的工作方式不同)。

【讨论】:

    【解决方案2】:

    来自 GNU Make 文档,

    5.3.1 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 中的任何位置,不必紧挨在目标之前。

    【讨论】:

    • 500 赏金等待来自man 的报价。谈论时间。 :P
    • @inLoveWithPython 好吧,info,实际上,但是,我想它确实帮助了安迪。我知道我有过这样的日子......
    • 如果有疑问,@derobert 的字面意思是:SHELL=/bin/bash 作为 Makefile 的第一行(或在注释之后)。
    • 如果你使用/usr/bin/env bash,它在PATH 中使用bash。但是如果只是SHELL := bash呢?
    • 如果您尝试从makefile 中$(info $(SHELL)) 并查看/bin/bash 时可能会出现一些混淆,请注意:这没有任何意义! GNU Make 从环境中继承变量,所以SHELL 变量来自环境,但是$(origin SHELL)environment 时它不会使用它(我的猜测)。
    【解决方案3】:

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

    bash -c "ls -al"
    

    代替:

    ls -al
    

    【讨论】:

    • 注意make忽略了环境变量SHELL的值。
    【解决方案4】:

    如果可移植性很重要,您可能不想依赖 Makefile 中的特定外壳。并非所有环境都提供 bash。

    【讨论】:

      【解决方案5】:

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

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

      【讨论】:

      • 当在名称sh 下调用时,bash 以兼容模式 (set -o posix) 运行。 OP 尝试使用的功能(进程替换)在此模式下不可用。
      【解决方案6】:

      一种可行的方法是将它放在目标的第一行:

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

      【讨论】:

        【解决方案7】:

        这不是问题的直接答案,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

        【讨论】:

        • 顺便说一句,您必须在回答中披露您是链接项目的作者。
        猜你喜欢
        • 2011-05-10
        • 2012-10-31
        • 2021-06-02
        • 2014-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多