背景
有次我在写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)