GNU Make中printf加cat管道输出异常及与Dash行为差异问题
Makefile中管道命令与直接执行Dash行为不一致的原因
问题场景
Makefile内容:
foo: printf '\x41\n' bar: printf '\x41\n' | cat
执行结果:
- 执行
make foo输出A - 执行
make bar输出\x41
系统默认shell指向Dash:
# ls -l /bin/sh lrwxrwxrwx 1 root root 4 Sep 12 04:41 /bin/sh -> dash
但直接在Dash终端中执行两条命令,输出均为\x41。
原因解析
GNU Make的命令执行逻辑差异
GNU Make处理命令时会区分两种情况:- 当命令是无shell元字符(管道、分号、重定向等)的单条命令时,Make会直接通过
exec系统调用执行该命令,不会启动shell进程。 - 当命令包含管道、分号等shell元字符时,Make会启动
/bin/sh(即Dash),将整个命令串交给shell解析执行。
- 当命令是无shell元字符(管道、分号、重定向等)的单条命令时,Make会直接通过
不同printf实现的转义支持差异
- 系统中存在两个printf:一个是GNU printf(来自coreutils包,路径通常为
/usr/bin/printf),它支持\x十六进制转义,能把\x41解析为字符A。 - Dash内置了自己的printf,不支持
\x转义,会将\x41原样输出。
- 系统中存在两个printf:一个是GNU printf(来自coreutils包,路径通常为
对应场景的具体解释
make foo:命令是单条无元字符的printf '\x41\n',Make直接执行/usr/bin/printf,所以输出A。make bar:命令包含管道|,Make启动Dash执行整个命令,此时用的是Dash内置的printf,输出\x41后传给cat,最终显示\x41。- 直接在Dash中执行时,无论是否加管道,都会调用Dash内置的printf,所以两条命令都输出
\x41。
内容的提问来源于stack exchange,提问作者Lone Learner
相关产品推荐
相关产品推荐

