【问题标题】:Makefile `echo -n' not workingMakefile `echo -n' 不工作
【发布时间】:2012-07-25 09:07:45
【问题描述】:

我试图让我的 Makefile 回显文本没有尾随的新行,但我做不到。我正在体验 OS X 上的行为(在 Linux 上一切正常)。

生成文件

a:
    @echo -n "hello"

b:
    @echo -n hello

c:
    @/bin/echo -n "hello"

输出:

$make a
-n hello
$make b
hello$make c
hello$

换句话说,make a 坏了。到底发生了什么?是否使用内置回声?显然双引号的存在会改变行为,但为什么呢?

更新

@chepner 发现,在 makefile 中使用 /bin/echo 的完整路径可以正确理解 -n 标志。

【问题讨论】:

    标签: bash makefile echo


    【解决方案1】:

    引号中的某些内容使make 感到困惑。您的代码对我来说表现相同,但以下代码按预期工作:

    help:
            @echo -n Shouldn\'t print a newline
    

    硬编码可执行文件的路径也可以:

    help:
            @/bin/echo -n "Shouldn't print a newline"
    

    echo 的 Mac OS X 手册页在讨论 shell 内置 echos 的存在时,提到 sh(1)echo 不支持 -n 选项,但失败了解释(对我来说,无论如何)为什么我的第一个替代方案有效。


    确认make 默认使用sh 执行命令。 Make manual 5.3.2 Choosing the Shell 指定此行为:

    用作shell的程序取自变量SHELL。如果 此变量未在您的 makefile 中设置,使用程序 /bin/sh 作为外壳。传递给 shell 的参数取自 变量.SHELLFLAGS。 .SHELLFLAGS 的默认值通常是 -c, 或 -ec 符合 POSIX 的模式。

    SHELL = bash
    help:
            @echo -n "Shouldn't print a newline"
            @echo -n Shouldn\'t print a newline
    

    两个 echo 语句的行为相同(不打印换行符)。所以没有那个变量,我们有bash 伪装成sh,但对这两行的评估不同。问题一:为什么?问题二:第二行是原生的bashecho还是/bin/echo,而不是模拟的shecho

    【讨论】:

    • 实际上,我刚刚意识到这一点,并正在改变我的问题以反映它。但是为什么 make 会感到困惑......我怎么能明确告诉 make 我想将 -n 标志传递给 echo(没有明确的路径?) make 使用某种内置的 echo 吗?
    • 整个配方使用$SHELL 指定的shell 执行,如果未设置该变量,则使用/bin/sh。所以通常情况下,如果有问题的 shell 有一个内置的,除非路径是硬编码的,否则它将使用它。这里奇怪的是,尽管$SHELL 被设置为'/usr/local/bin/bash'(无论如何对我来说),问题行似乎是使用sh 内置执行的,而不是bash内置。
    • 我之前遇到了 -e 标志的问题,所以所有标志都因为一些奇怪的原因而造成混淆......
    【解决方案2】:

    问题来自两个事实的不幸交互。

    首先,make 有两种操作模式,具体取决于要运行的配方的复杂性:

    • 如果命令简单make 将直接使用其内置命令运行配方。这就是您的 b 案例中发生的情况。
    • 如果命令是复杂make 将生成一个 shell 来解释和运行配方。这就是您的 a 案例中发生的情况。

    其次,make 使用 /bin/sh 作为 shell,但 /bin/sh 的功能在 Mac OS X 和 Linux 上的实现方式不同:

    • 在 Mac OS X 上,/bin/sh 的功能由bash 实现。同样在 Mac OS X 上,bash 使用--enable-strict-posix-default 编译。此标志的一个后果是echo 命令不理解-n 标志。
    • 在 Linux 上,/bin/sh 的功能由 dash 实现,这在 POSIX 规范方面不太严格。因此,-n 标志在 echo 命令中实现。

    顺便说一句,Makefile buitlin echo 命令理解 -n 标志,这解释了为什么 b 案例始终有效。

    解决问题的简洁和便携的方法是将@echo -n 食谱替换为@printf 食谱。

    【讨论】:

    • 有点相关:至少在 Mac Lion 10.7 上,root 的默认 shell 是 /bin/sh 而不是 /bin/bash。最好使用 'chsh' 命令将其更改为 /bin/bash(无需参数),以便 'echo -n' 在 .bashrc 等中工作。
    【解决方案3】:

    echo 是一个内置的 bash shell,但是当你从 makefile 运行它时,它是程序版本

    【讨论】:

    • -n 被内置程序和独立程序支持。
    • 程序版本(/bin/echo)实际上支持-n,所以如果Makefile使用/bin/echo,它会正常工作。
    猜你喜欢
    • 1970-01-01
    • 2012-11-07
    • 2012-04-24
    • 1970-01-01
    • 1970-01-01
    • 2023-03-16
    • 1970-01-01
    • 2012-06-26
    • 1970-01-01
    相关资源
    最近更新 更多