如何使用 bash 在一组参数上并行执行多个命令,如果其中至少一个失败则失败
How do I execute multiple commands in parallel on an array of parameters with bash, and fail if at least one of them failed
我有一个 bash 脚本,其中的函数需要 运行 与不同的参数并行。
我需要知道是否至少有一个执行失败(返回非零)——不管有多少失败。
该命令接受一组执行参数。
由于高负载,我需要将并发限制为 4 个并发 运行。
我还需要在父进程(运行s bash 脚本)
中打印日志
这是我运行宁的功能:
function run_and_retry {
EXIT_STATUS=0
$COMMAND || EXIT_STATUS=$?
if [ $EXIT_STATUS -ne 0 ]; then
EXIT_STATUS=0
$COMMAND || EXIT_STATUS=$?
fi
return $EXIT_STATUS
}
我尝试过使用 GNU parallel 和 xargs,但都遇到了问题。
使用 xargs:(无法从中获取退出状态,当我在 TravisCI 中 运行 时它也不起作用)
PARAMETERS=(first-parameter second-parameter third-parameter)
export -f run_and_retry
echo "${PARAMETERS[@]}" | xargs -P 4 -n 1 -I {} bash -c "run_and_retry {}"
与 GNU 并行:
PARAMETERS=(first-parameter second-parameter third-parameter)
export -f run_and_retry
parallel -j 4 -k --lb 2 run_and_retry {} ::: echo "${PARAMETERS[@]}"
I need to know if at least one of the executions failed (returned non-zero)
来自posix xargs:
EXIT STATUS
1-125
A command line meeting the specified requirements could not be assembled, one or more of the invocations of utility returned a non-zero exit status, or some other error occurred.
man xargs好像有点不一样:
EXIT STATUS
123 if any invocation of the command exited with status 1-125
但我会检查命令的 return 状态和 return 函数中的预定义数字(例如 1)来处理它。
parameters=(1 2 3 fail)
func() {
COMMAND=sleep
# I guess OP intends to try running COMMAND twice
if ! "$COMMAND" 0."" && ! "$COMMAND" 0.""; then
return 1
fi
}
export -f func
if printf "%s[=10=]" "${parameters[@]}" | xargs -0 -P4 -n1 -t -- bash -c 'func ' -- ; then
echo "Success!"
else
echo "Error!"
fi
在线版本可在 tutorialspoint 获得。
好吧,我们甚至可以手动计算孩子的数量,使用 wait -n
变得非常简单。来自 Whosebug - WAIT for “1 of many process” to finish:
bash 4.3 added a -n flag to the built-in wait command, which causes the script to wait for the next child to complete.
所以我们可以:
cnt=0
failed=false
for i in "${parameters[@]}"; do
( func "$i" ) &
if (( cnt < 4 )); then
cnt=$((cnt+1))
else
# handle more then 4 processes
if ! wait -n; then
failed=true
fi
fi
done
# handle still running processes after all have been forked
for i in $(seq $cnt); do
if ! wait -n; then
failed=true
fi
done
if "$failed"; then
echo "One of the jobs failed!"
fi
您所以接近正确的 GNU Parallel 语法:
COMMAND=echo
PARAMETERS=(first-parameter second-parameter third-parameter)
parallel -j 4 -k --retries 2 "$COMMAND" {} ::: "${PARAMETERS[@]}" ||
echo $? commands failed. More than 99 if $? = 100
或者如果你真的坚持自己重试:
PARAMETERS=(first-parameter second-parameter third-parameter)
export -f run_and_retry
parallel -j 4 -k run_and_retry {} ::: "${PARAMETERS[@]}" ||
echo One or more commands failed
我有一个 bash 脚本,其中的函数需要 运行 与不同的参数并行。 我需要知道是否至少有一个执行失败(返回非零)——不管有多少失败。
该命令接受一组执行参数。 由于高负载,我需要将并发限制为 4 个并发 运行。 我还需要在父进程(运行s bash 脚本)
中打印日志这是我运行宁的功能:
function run_and_retry {
EXIT_STATUS=0
$COMMAND || EXIT_STATUS=$?
if [ $EXIT_STATUS -ne 0 ]; then
EXIT_STATUS=0
$COMMAND || EXIT_STATUS=$?
fi
return $EXIT_STATUS
}
我尝试过使用 GNU parallel 和 xargs,但都遇到了问题。
使用 xargs:(无法从中获取退出状态,当我在 TravisCI 中 运行 时它也不起作用)
PARAMETERS=(first-parameter second-parameter third-parameter)
export -f run_and_retry
echo "${PARAMETERS[@]}" | xargs -P 4 -n 1 -I {} bash -c "run_and_retry {}"
与 GNU 并行:
PARAMETERS=(first-parameter second-parameter third-parameter)
export -f run_and_retry
parallel -j 4 -k --lb 2 run_and_retry {} ::: echo "${PARAMETERS[@]}"
I need to know if at least one of the executions failed (returned non-zero)
来自posix xargs:
EXIT STATUS
1-125
A command line meeting the specified requirements could not be assembled, one or more of the invocations of utility returned a non-zero exit status, or some other error occurred.
man xargs好像有点不一样:
EXIT STATUS
123 if any invocation of the command exited with status 1-125
但我会检查命令的 return 状态和 return 函数中的预定义数字(例如 1)来处理它。
parameters=(1 2 3 fail)
func() {
COMMAND=sleep
# I guess OP intends to try running COMMAND twice
if ! "$COMMAND" 0."" && ! "$COMMAND" 0.""; then
return 1
fi
}
export -f func
if printf "%s[=10=]" "${parameters[@]}" | xargs -0 -P4 -n1 -t -- bash -c 'func ' -- ; then
echo "Success!"
else
echo "Error!"
fi
在线版本可在 tutorialspoint 获得。
好吧,我们甚至可以手动计算孩子的数量,使用 wait -n
变得非常简单。来自 Whosebug - WAIT for “1 of many process” to finish:
bash 4.3 added a -n flag to the built-in wait command, which causes the script to wait for the next child to complete.
所以我们可以:
cnt=0
failed=false
for i in "${parameters[@]}"; do
( func "$i" ) &
if (( cnt < 4 )); then
cnt=$((cnt+1))
else
# handle more then 4 processes
if ! wait -n; then
failed=true
fi
fi
done
# handle still running processes after all have been forked
for i in $(seq $cnt); do
if ! wait -n; then
failed=true
fi
done
if "$failed"; then
echo "One of the jobs failed!"
fi
您所以接近正确的 GNU Parallel 语法:
COMMAND=echo
PARAMETERS=(first-parameter second-parameter third-parameter)
parallel -j 4 -k --retries 2 "$COMMAND" {} ::: "${PARAMETERS[@]}" ||
echo $? commands failed. More than 99 if $? = 100
或者如果你真的坚持自己重试:
PARAMETERS=(first-parameter second-parameter third-parameter)
export -f run_and_retry
parallel -j 4 -k run_and_retry {} ::: "${PARAMETERS[@]}" ||
echo One or more commands failed