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

背景

有次我在写makfile时,用echo -e要显示带颜色的文字,命令如下:
echo -e “Full Version is:\033[31m\033[1m v1.0 \033[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:\033[31m\033[1m v1.0 \033[0m";
Full Version is: v1.0
$ exit
exit
$
$ /bin/dash
$ echo -e "Full Version is:\033[31m\033[1m v1.0 \033[0m";
-e Full Version is: v1.0
$ exit
$

makefile用的是哪个shell

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

$ ls -l /bin/sh
0 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使用的是bash
jeremy@compute1:~/xx$ echo $0
-bash  同上
jeremy@compute1:~/xx$ echo -e "\$ \b()"
输出为$()
jeremy@compute1:~/xx$ echo -e "\$() + \%.o"
输出为$() + %.o   

echo的选项:

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

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

#SHELL=/bin/bash

.PHONY: clean all
all:
        @echo $(SHELL)
        @echo -e "\$ \b()" 

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 all
all:
        @echo $(SHELL)
        @echo -e "\$ \b()" 

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)

猜你喜欢

转载自blog.csdn.net/haifeng_gu/article/details/73332242