如何在Bash脚本中检测CreateReactApp编译成功后执行后续命令并保持服务活跃
解决React E2E服务启动后触发后续命令的问题
我来帮你搞定这个需求——你要的是让yarn run start:e2e在watch模式下持续运行,同时在它输出"Compiled successfully"后,自动执行后续的测试命令对吧?之前的方法之所以失败,主要是因为管道会把子进程和主进程绑定,导致服务被意外终止,或者后续命令没法触发。下面给你两个靠谱的解决方案:
方案一:使用Bash协程(Coproc)
这是最简洁的方式,不需要临时文件,直接利用Bash的协程特性捕获输出:
# 启动协程运行React服务,强制行缓冲确保实时输出 coproc YARN { stdbuf -o0 yarn run start:e2e; } # 监听协程的输出,直到匹配到编译成功的日志 while read -r line <&"${YARN[0]}"; do # 实时打印服务日志(可选,不需要可以删掉) echo "$line" if [[ "$line" == *"Compiled successfully"* ]]; then # 匹配到后跳出循环,继续执行后续命令 break fi done # 这里放你的后续命令 echo "I WANT TO SEE THIS LOG" # 比如执行E2E测试:cypress run # cypress run # 如果后续需要停止React服务,可以用以下命令 # kill "${YARN_PID}"
方案原理:
coproc会在后台启动yarn run start:e2e,同时创建一个文件描述符让我们能捕获它的输出stdbuf -o0强制服务的输出为行缓冲,避免因为输出不是终端而出现块缓冲,导致无法实时读到日志- 匹配到目标字符串后跳出循环,协程里的React服务依然会在后台持续运行,不会被终止
方案二:后台进程+临时文件标记
如果你的Bash版本不支持协程(比如某些旧版本),可以用这个方法:
# 启动React服务到后台,重定向输出到监听进程,强制行缓冲 stdbuf -o0 yarn run start:e2e > >(while read -r line; do echo "$line" if [[ "$line" == *"Compiled successfully"* ]]; then # 创建临时文件标记服务已就绪 touch .e2e-service-ready # 退出监听进程,不影响后台的React服务 exit 0 fi done) 2>&1 & # 等待临时文件出现,轮询检查服务是否就绪 while [[ ! -f .e2e-service-ready ]]; do sleep 0.5 done # 清理临时文件 rm .e2e-service-ready # 执行后续命令 echo "I WANT TO SEE THIS LOG" # 你的测试命令...
为什么之前的方法不行?
- 第一种if+grep的方法:
grep匹配到字符串后会立即退出,导致管道关闭,React服务会收到SIGPIPE信号被终止,而且then exit 0会直接退出整个脚本,后续的echo根本没机会执行。 - 第二种while循环的方法:管道会把while循环放到子shell里,子shell里的
exit 0只会退出子shell,主shell会继续等待管道的另一端(React服务)结束,但服务是watch模式不会结束,所以主shell会一直卡住,后续命令无法执行。
注意事项
- 一定要加上
stdbuf -o0:Node.js程序在输出到非终端(比如管道、文件)时,默认会用块缓冲,导致日志不会实时输出,stdbuf可以强制改为行缓冲,确保我们能及时捕获到"Compiled successfully"的日志。 - 如果你的React服务输出的是"Compiled successfully!"(带感叹号),记得把脚本里的匹配字符串改成对应的内容。
内容的提问来源于stack exchange,提问作者PsykoMantrix
相关产品推荐
相关产品推荐

