Makefile中的`echo -n`无效

33

我想让我的Makefile在输出文本时去掉行尾的换行符,但是无法做到。在OS X上出现了这种情况(在Linux上一切正常)。

Makefile

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出了问题。到底发生了什么?是make使用了内置的echo命令吗?显然,双引号的存在改变了行为,但是为什么?

更新

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

3个回答

35
问题源于两个事实不幸地相互作用。
首先,make有两种操作模式,具体取决于要运行的配方的复杂性:
如果命令很简单,则make将使用其内置命令直接运行配方。这就是您的“b”情况发生的情况。
如果命令较为复杂,则make将生成一个shell来解释和运行该配方。这就是您的“a”情况发生的情况。
其次,make使用/bin/sh作为shell,但Mac OS X和Linux上的/bin/sh的功能实现方式不同:
在Mac OS X上,/bin/sh的功能由bash实现。此外,在Mac OS X上,bash编译时使用--enable-strict-posix-default标志。此标志的一个后果是echo命令不理解-n标志。
在Linux上,/bin/sh的功能由dash实现,dash对POSIX规范不那么严格。因此,echo命令实现了-n标志。
顺便说一下,Makefile内置的echo命令理解-n标志,这就解释了为什么b情况总是有效。
修复问题的干净便携的方法是将@echo -n 配方替换为 @printf 配方。

有点相关:在Mac Lion 10.7上,root的默认shell是/bin/sh而不是/bin/bash。最好使用“chsh”命令将其更改为/bin/bash(无需参数),以便在.bashrc等中工作“echo -n”。 - RichVel

29

关于引号的问题使得make感到困惑。您的代码对我来说表现相同,但是以下内容可以按预期工作:

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

将可执行文件路径硬编码也可以工作:
help:
        @/bin/echo -n "Shouldn't print a newline"

Mac OS X的echo man页面讨论了shell内置的echo是否存在时,提到sh(1)echo不支持-n选项,但是没有解释为什么我的第一个替代方案有效。


make使用默认的sh执行命令。 Make手册5.3.2选择Shell指定此hehavrior:

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

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

两个echo语句都表现相同(不打印换行符)。因此,如果没有那个变量,我们有 bash 假扮成 sh,但是对这两行进行了不同的评估。问题1:为什么?问题2:第二行是本机的 bash echo 还是 /bin/echo,而不是模拟的 sh echo吗?


实际上,我刚刚意识到这一点,并正在修改我的问题以反映它。但是为什么make会混淆...我如何使其明确地传递-n标志给echo(而不使用显式路径?)make是否使用某种内置的echo命令? - Chris
整个脚本使用由$SHELL指定的shell执行,如果该变量未设置,则使用/bin/sh。因此,通常情况下,如果所使用的shell具有内置功能,则会使用该内置功能,除非路径是硬编码的。奇怪的是,尽管$SHELL被设置为'/usr/local/bin/bash'(至少对我来说是这样),但问题行似乎是使用sh内置而不是bash内置执行的。 - chepner
1
我之前遇到了“-e”标志的问题,所以所有的标志都让make混淆了,原因很奇怪... - Anonymous Penguin

3

echo是bash shell内置命令,但当你在makefile中运行它时,它是程序版本。


1
“-n” 被内置程序和独立程序都支持。 - chepner
2
程序版本(/bin/echo)实际上支持-n选项,因此如果Makefile使用/bin/echo,则会正常工作。 - Chris

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接