如何捕获Makefile中test命令的返回状态并排查执行异常?
解决Makefile中
test ! -s *.txt返回状态2的问题 我来帮你拆解一下问题出在哪,然后给出几种靠谱的解决办法:
为什么make test1会返回状态2?
当你在Makefile里写test ! -s *.txt时,shell会把*.txt展开成当前目录下所有匹配的文本文件(比如a.txt b.txt),这就导致实际执行的命令变成了:
test ! -s a.txt b.txt
而test命令的单目运算符! -s(检查文件是否为空)只能接收一个路径参数,给它传两个参数就触发了语法错误——shell里命令语法错误的返回状态通常就是2,这就是你遇到的问题。
解决方案:检查所有.txt文件是否为空
如果你想要的逻辑是「所有.txt文件都为空时返回0,只要有一个非空就返回1」,可以用以下几种写法:
方法1:Shell循环逐个检查
这是最直观的写法,循环遍历每个txt文件,只要发现非空文件就立即退出并返回失败状态:
test1: for file in *.txt; do \ test ! -s "$$file" || exit 1; \ done
- 用
$$file是因为Makefile里$需要转义,否则会被Make当成变量解析; || exit 1表示如果当前文件非空(test ! -s失败),就立即退出shell进程,让make感知到失败。
方法2:用find命令实现(更简洁)
借助find命令查找非空的txt文件,只要找到任何一个就返回失败:
test1: ! find . -maxdepth 1 -name "*.txt" -type f -not -empty | grep .
find命令会查找当前目录下(-maxdepth 1限制不递归子目录)非空的txt文件;- 如果找到匹配的文件,
grep .会有输出,前面的!取反后整个命令返回1(失败); - 如果所有文件都为空,
find没有输出,grep .返回非0,!取反后返回0(成功)。
顺便说下test2的问题
你的test2用了Make的foreach函数,展开后会变成:
test ! -s a.txt; test ! -s b.txt;
这种写法的问题是:shell会依次执行每个test命令,但整个命令序列的返回状态只取决于最后一个命令的结果。比如如果a.txt非空、b.txt为空,第一个test返回1但第二个返回0,make会认为这个目标执行成功,这显然不符合「所有文件都为空才成功」的需求。如果要修复test2,可以改成用&&连接每个命令,确保只要有一个失败就终止:
test2: $(foreach file, $(wildcard *.txt), test ! -s ${file} && ) true
这里最后加true是为了避免foreach展开后最后多一个&&导致语法错误,逻辑上只要所有test都成功,最后执行true返回0,否则中途就会失败。
内容的提问来源于stack exchange,提问作者sarbjit
相关产品推荐
相关产品推荐

