我有这个 bash 脚本来启动一些服务器:
services=(
account-service
reminder-service
activity-service
socket-service
chat-service
web-app
)
for s in "${services[@]}"; do
(
set -e;
cd "$s"
git pull
npm start || exit 1 # always fails
) &
sleep 1;
done
wait;
有时该git pull
命令会失败。但故障深深地存在于日志中,而且并不总是显而易见。如果子 shell 中的命令之一以 1 退出,如何中止整个脚本?
答案1
嗯,也许:将wait
语句更改为:
while true; do
wait -n || exit 1 # if one of the background jobs failed, abort
[[ "$(jobs)" ]] && break # exit this loop if no more jobs
done
完全未经测试。我不确定jobs
在非交互式 shell 中是否按预期工作。
答案2
这里有几个问题:
- 如果子 shell 中的命令失败,则使整个脚本中止。
- 提高发生的任何错误的可见性。
我将从第二个开始。该问题包含答案的种子:记录错误,但日志的内容对用户来说并不明显。因此,记录错误(在临时日志文件中)并在最后显示它们:
服务=( 账户服务 提醒服务 活动服务 套接字服务 聊天服务 网络应用程序 ) 错误文件=$(mktemp) 对于“${services[@]}”中的 s;做 ( 设置-e; cd“$s” git拉 || { 回声“$s”>>“$errfile” 1号出口 } 回声“$cmd”|巴什 ) & 睡觉 1 完毕 等待 if [ -s "$errfile" ] 然后 echo“以下服务有错误:” 猫“$errfile” 菲 rm -f "$errfile"
解决问题 #1 的最简单方法是定期检查子 shell 中的代码[ -s "$errfile" ]
,并在出现任何问题时中止自身。一个更雄心勃勃的方法是让主(父)进程跟踪子进程的 PID 并向它们发送信号。我不确定如果没有wait -n
. (也许您可以让有错误的子级向父级发送信号以将其从wait
. 中打破。)