Makefile中echo -e 以及 输出$|和%.o 这两个字符串的问题

Makefile中echo -e 以及 输出$|和%.o 这两个字符串的问题

背景

有次我在写makfile时,用echo -e要显示带颜色的文字,命令如下:
echo -e “Full Version is:33[31m33[1m v1.0 33[0m”;
该命令在控制台中单独执行都显示正常,效果如下:

Full Version is: v1.0

可以放在makefile中一运行, 结果把-e也显示出来:

-e Full Version is: v1.0

原因

这是由于不同的shell(一个是bash,一个是dash)造成的两种不同的结果,即在bash下正常,在dash下就多显示了一个-e。
从Ubuntu 6.10开始,默认使用的shell是dash,而不是bash,原因是dash更快、更高效,使用dash可以加快启动速度。
我们可以做如下实验来验证下,先启用bash运行下指令,再启用dash试试:

$ /bin/bash$ echo -e "Full Version is:33[31m33[1m v1.0 33[0m";Full Version is: v1.0$ exitexit$$ /bin/dash$ echo -e "Full Version is:33[31m33[1m v1.0 33[0m";-e Full Version is: v1.0$ exit$

makefile用的是哪个shell

makefile默认用的shell是/bin/sh。但/bin/sh紧紧是个链接文件,到底用的是什么shell程序可以通过ls查看:

$ ls -l /bin/sh0 lrwxrwxrwx 1 root root 4  6月 20 2012 /bin/sh -> dash

而系统默认的shell可以通过系统环境变量SHELL查看,当前shell可以通$0查看:

$ echo $SHELL/bin/bash$ echo $0-bash

至此,之所以会出现前面所述的问题,就是这个原因了:在makefile中用的是/bin/dash,而在控制台中用的是/bin/bash。

那makefile能不能显式地指定由哪个shell程序来运行命令呢?答案是肯定的。makefile本身有个环境变量也叫SHELL(跟系统环境变量SHELL同名,但不一样),我们可以在makefile中明确地给他赋值,以指明用哪个shell程序来解析命令。如SHELL=/bin/bash。

我在makefile最前面加上SHELL=/bin/bash,问题就解决了。

我试了下网上部分同学说的在Makefile开头使用 #!/bin/bash 的方式,但似乎不起作用,echo $(SHELL) 依然是/bin/sh (即指向了默认的/bin/dash)。


现在我有另一个问题,就是怎么在Makefile中通过echo打印出$()和%.o 这两个字符串?

我们知道,$()和% 在shell中属于特殊字符,打印时需要escape(转义)。

  • $(command) 相当于2个反引号`command`,也用作命令替换,即先执行括号中的命令,然后返回命令执行的结果。
  • % 在参数替换(parameter substitution)中,可以作为模式匹配。在算术运算中,这个是求模操作符。

在ubuntu终端命令行下直接执行下列命令输出是OK的,如下:

jeremy@compute1:~/xx$ echo $SHELL/bin/bash  这个输出说明当前shell使用的是bashjeremy@compute1:~/xx$ echo $0-bash  同上jeremy@compute1:~/xx$ echo -e "$ ()"输出为$()jeremy@compute1:~/xx$ echo -e "$() + %.o"输出为$() + %.o

echo的选项:

-n 不要在最后自动换行-e 若字符串中出现以下字符,则特别加以处理,而不会将它当成一般文字输出:   a 发出警告声;    删除前一个字符;(如单词间的空格)   c 最后不加上换行符号;   f 换行但光标仍旧停留在原来的位置;    换行且光标移至行首;    光标移至行首,但不换行;    插入tab;   v 与f相同;    插入字符;   nn 插入nnn(八进制)所代表的ASCII字符;–help 显示帮助–version 显示版本信息

但是在Makefile中,使用同样的echo指令,同样是bash,输出结果却不对。。。
Makefile的内容如下(其中第一行SHELL=/bin/bash先注释掉):

#SHELL=/bin/bash.PHONY: clean allall:        @echo $(SHELL)        @echo -e "$ ()" clean:        @echo -e "$() + %.o"

执行结果如下:

jeremy@compute1:~/xx$ make all/bin/sh-e()jeremy@compute1:~/xx$ make clean -e  + %.o

现在将Makefile中第一行SHELL=/bin/bash启用:

SHELL=/bin/bash.PHONY: clean allall:        @echo $(SHELL)        @echo -e "$ ()" clean:        @echo -e "$() + %.o"

执行结果如下:

jeremy@compute1:~/xx$ make all/bin/bash   启用SHELL=/bin/bash后,()  前面的-e确实没有了,但为何不是输出$()呢??jeremy@compute1:~/xx$ make clean  + %.o

结论:

  • 在Makefile中第一行设定SHELL=/bin/bash后,echo输出就不会显示-e选项了
  • echo格式化输出(-e 参数)需要bash支持
  • 还是没解决Makefile中echo打印出$()和%.o 这两个字符串。求高人指点,谢谢!!



欢迎大家在评论中指正!

Reference

makefile中使用echo -e引发的思考(涉及dash和bash)

推荐阅读