我有一个bash脚本,我想在该脚本中并行运行两个进程,如果两个进程中的任何一个返回非零,脚本都会失败。我最初尝试的一个最小示例是:
#!/bin/bash
set -e
(sleep 3 ; true ) &
(sleep 4 ; false ) &
wait %1 && wait %2
echo "Still here, exit code: $?"
按预期,这不会打印消息,因为wait %1 && wait %2
失败,并且脚本由于set -e
而退出。但是,如果将wait
颠倒过来,使得第一个具有非零状态(wait %2 && wait %1
),则会显示消息 :
$ bash wait_test.sh
Still here, exit code: 1
将每个wait
放在自己的行中可以按我的意愿工作,如果两个进程中的任何一个失败,则退出脚本,但是事实证明它不能与&&
一起使用,这使我怀疑自己在我误会了这里的东西。
任何人都可以解释发生了什么事吗?
答案 0 :(得分:2)
您可以使用 GNU Parallel 及其“失败处理” 轻松地实现所需的功能。
通常,它将并行运行与CPU内核数量一样多的作业。
您可以尝试使用此方法,它显示“如果一个或多个作业失败,则退出状态失败” :
#!/bin/bash
cat <<EOF | parallel --halt soon,fail=1
echo Job 1; exit 0
echo Job 2; exit 1
EOF
echo GNU Parallel exit status: $?
示例输出
Job 1
Job 2
parallel: This job failed:
echo Job 2; exit 1
GNU Parallel exit status: 1
现在运行它,使任何作业都不会失败:
#!/bin/bash
cat <<EOF | parallel --halt soon,fail=1
echo Job 1; exit 0
echo Job 2; exit 0
EOF
echo GNU Parallel exit status: $?
示例输出
Job 1
Job 2
GNU Parallel exit status: 0
如果您不喜欢heredoc
语法,可以将作业列表放在名为jobs.txt
的文件中,如下所示:
echo Job 1; exit 0
echo Job 2; exit 0
然后运行:
parallel --halt soon,fail=1 < jobs.txt
答案 1 :(得分:1)
从bash
手册部分开始,有关set
的用法
-e 如果管道(可能由一个简单命令组成),列表或复合命令(请参见上面的SHELL GRAMMAR)以非零状态退出,则立即退出。如果失败的命令是一会儿或直到关键字之后紧随其后的命令列表的一部分,if或elif保留字之后的部分测试,&&或||中执行的任何命令的部分,则外壳程序不会退出。列出除最后一个&&或|| 之后的命令,管道中除最后一个命令之外的任何命令,或者该命令的返回值用!取反。如果除子shell之外的复合命令由于在-e被忽略时命令失败而返回非零状态,则该shell不会退出。在退出外壳程序之前,将执行ERR陷阱(如果已设置)。此选项分别适用于Shell环境和每个子Shell环境(请参见上面的COMMAND EXECUTION ENVIRONMENT),并且可能导致子Shell在执行子Shell中的所有命令之前退出。
tl; dr
在bash脚本中,用于这样的命令列表
command1 && command2
command1
在单独的环境中运行,因此它不会影响脚本的执行环境。但是command2
在当前环境中运行,因此可能会影响