-
-
shell+Makefile,坑我晚下班
-
发表于:
2024-12-6 12:49
2110
-
昨天遇到一个这样的问题:
test
|- test.sh
|- 1.txt
|- hello
|- test.c
|- Makefile
|- 2.txt
test.sh读取1.txt,每读一行,执行一下"make clean; make pat=22":
#!/bin/bash
while read line || [[ -n "${line}" ]]; do
echo "${line}"
cd hello
make clean; make pat=22
cd ..
done < ./1.txt
1.txt内容如下,所以按道理,test.sh应该循环3次:
1111111
aaaaaaa
AAAAAAA
Makefile用于编译test.c,每次执行,都会执行一条shell命令,并将结果赋值给var变量:
var := $(shell grep $(pat) 2.txt)
test: test.o
@echo "$(pat), $(var) ......."
gcc test.c -o test -g -Wall
.PHONY: clean
clean:
rm test test.o -f
test.c(不重要):
#include <stdio.h>
int main()
{
printf("hello\n");
return 0;
}
2.txt:
2222222
bbbbbbb
BBBBBBB
执行结果:
test.sh只循环了1次,但是期望循环3次。
分析:
实际项目的代码,要复杂的多,先通过不断的注释执行,将原因锁定到Makefile的这一行:"var := $(shell grep $(pat) 2.txt)";
但是这一行只读不写,并且读取对象还是2.txt,并不会影响1.txt内容;
从test.sh的打印结果看,第一遍执行"make clean; make pat=22",看着也没什么问题,脚本并没有退出或卡住,因为test可执行文件编译出来了,循环结束位置打印的分割线,也显示了;
将var赋值语句换成"var := $(shell cat 2.txt | grep $(pat))",语义一样,只是方式不同,竟然就正常了;
为了搞清楚到底怎么回事,就构造了以上demo,然后想到,执行"make clean"时,没有传pat参数,会导致"grep $(pat) 2.txt",等效于"grep 2.txt",手动执行这条命令是会卡住的,先忽略是否现象吻合,这确实就是问题所在,在$(pat)外面加个双引号,即可解决问题。
疑惑:
但是,从test.sh的打印结果看,并不是"make clean"卡住了(通过ps命令,也能确认make clean和grep命令并没有继续在执行),而是test.sh脚本的循环中断了。
猜测:
跟Makefile中的shell命令卡住有关,因为以上4中的修改方式,也没在$(pat)外面加双引号,不同的是,手动执行这条命令,会失败,但不会卡住,就没有导致test.sh的循环中断。
进一步想:
test.sh会创建一个新的进程,执行make命令,make也会创建一个新的进程,执行grep命令,孙子进程理论上会卡住,但从结果来看,test.sh却能继续往后执行,所以大概可以推测,make对于会卡住的shell命令,会有一套自己的处理,总之也是瞬间就执行完了。至于为什么能影响到test.sh进程,而且影响结果还这么奇怪,暂时还没能搞清楚。
在test.sh循环结尾,显示一下1.txt,也还是完整的:
[注意]传递专业知识、拓宽行业人脉——看雪讲师团队等你加入!