如果在其中创建错误或其创建的任何后台作业中,则退出bash脚本

时间:2016-03-30 17:46:36

标签: bash shell npm build-process

背景

我正在使用bash脚本来自动构建位于同一目录中的六个项目的过程。每个项目都有两个要运行的脚本来构建它:

cout << "Tiene los atributos siguientes: \n";
cout << "Puntos de Vida (PV)... " << luch_bas[0] << endl;
cout << "Puntos de Magia (PM)..." << luch_bas[1] << endl;
cout << "Fuerza (FUE) ..."        << luch_bas[2] << endl;
cout << "Rapidez (RAP) ..."       << luch_bas[3] << endl;
cout << "Precisión (PRE) ..."     << luch_bas[4] << endl;
cout << "Sabiduría (SAB) ..."     << luch_bas[5] << endl;
cout << "Espíritu (ESP) ..."      << luch_bas[6] << endl;

第一行将从npm获取所有依赖项。由于此步骤耗时最长,并且由于项目可以同时获取其依赖项,因此我使用后台作业来并行获取所有内容。 (即:npm install npm run build

第二行将使用这些依赖项来构建项目。由于这必须在完成所有步骤1之后发生,因此我在其间运行npm install &命令。请参阅下面的代码段。

问题

我希望在任何后台作业发生错误时立即退出脚本,或者之后发生wait步骤。

我正在使用npm run build,但是这不适用于后台作业,因此如果一个项目无法安装它的依赖项,其他一切都会继续。

以下是我的脚本现在看起来如何的简化示例。

build.sh

set -e

同样,如果在任何时候发生错误,我不想继续在脚本中执行任何操作,这适用于父作业和后台作业。这可能吗?

2 个答案:

答案 0 :(得分:5)

收集后台作业的PID;然后,使用wait收集每个的退出状态,在该循环中轮询的任何PID第一次退出非零。

install_pids=( )
for dir in ./projects/**/; do
  (cd "$dir" && exec npm install) & install_pids+=( $! )
done
for pid in "${install_pids[@]}"; do
  wait "$pid" || exit
done

以上虽然简单但有一点需要注意:如果列表中的项目 late 在列表中较早的项目之前退出非零,则在列表中的该点之前不会观察到轮询。要解决这个问题,您可以反复遍历整个列表:

install_pids=( )
for dir in ./projects/**/; do
  (cd "$dir" && exec npm install) & install_pids+=( $! )
done
while (( ${#install_pids[@]} )); do
  for pid_idx in "${!install_pids[@]}"; do
    pid=${install_pids[$pid_idx]}
    if ! kill -0 "$pid" 2>/dev/null; then # kill -0 checks for process existance
      # we know this pid has exited; retrieve its exit status
      wait "$pid" || exit
      unset "install_pids[$pid_idx]"
    fi
  done
  sleep 1 # in bash, consider a shorter non-integer interval, ie. 0.2
done

但是,因为这次调查,会产生额外的开销。这可以通过捕获SIGCHLD并在触发陷阱时引用jobs -n(以获取自上次轮询后状态发生更改的作业列表)来避免。

答案 1 :(得分:1)

Bash并不是为了这样的并行处理而做的。为了实现你想要的,我必须编写一个函数库。如果可能的话,我建议寻找一种更适合这种语言的语言。

循环通过pids的问题,例如......

#!/bin/bash
pids=()
f() {
   sleep $1
   echo "no good"
   false
}

t() {
   sleep $1
   echo "good"
   true
}

t 3 &
pids+=$!

f 1 &
pids+=$!

t 2 &
pids+=$!
for p in ${pids[@]}; do
   wait $p || echo failed
done

问题是&#34;等待&#34;将等待第一个pid,如果其他pid在第一个pid完成之前完成,则您将不会捕获退出代码。上面的代码在bash v4.2.46上显示了这个问题。 false命令应该产生永远不会被捕获的输出。