我对bash有点新,我需要并行运行几百次短命令,但顺序打印输出。该命令打印一个相当短的输出到stdout,这是我不想松动或使其与另一个线程的输出混淆/混淆。在Linux中是否有办法运行多个命令(例如,并行不超过N个线程),以便顺序打印所有命令输出(按任何顺序,只要它们不重叠)。
当前bash脚本(完整代码here)
declare -a UPDATE_ERRORS
UPDATE_ERRORS=( )
function pull {
git pull # Assumes current dir is set
if [[ $? -ne 0 ]]; then
UPDATE_ERRORS+=("error message")
fi
for f in extensions/*; do
if [[ -d $f ]]; then
########## This code should run in parallel, but output of each thread
########## should be cached and printed sequentially one after another
########## pull function also updates a global var that will be used later
pushd $f > /dev/null
pull
popd > /dev/null
fi
done
if [[ ${#UPDATE_ERRORS[@]} -ne 0 ]]; then
# print errors again
fi
答案 0 :(得分:3)
您可以使用flock
。我已经模仿了类似的情况进行测试。 do_the_things
proc生成时间输出重叠。在for循环文本生成中同时调用多次。输出应该变得混乱,但输出被送到过程locked_print
,它等待锁定被释放然后将收到的输入打印到stdout。从管道内部调用程序需要输出。
#!/bin/bash
do_the_things()
{
rand="$((RANDOM % 10))"
sleep $rand
for i in `seq 1 10`; do sleep 1; echo "${rand}-$i"; done
}
locked_print()
{
echo Started
flock -e testlock cat
}
export -f do_the_things
export -f locked_print
for f in a b c d; do
(do_the_things | locked_print) &
done
wait
答案 1 :(得分:1)
尝试这样的事情。我没有/使用git
所以我在我的版本中做了一个虚拟命令来模拟它。
#!/bin/bash
declare -a ERRORS
ERRORS=( )
function pull {
cd "$1"
echo Starting pull in $1
for i in {0..9}; do echo "$1 Output line $i";done
sleep 5
echo "GITERROR: Dummy error in directory $1"
}
export -f pull
for f in extensions/*; do
if [[ -d $f ]]; then
########## This code should run in parallel, but output of each thread
########## should be cached and printed sequentially one after another
########## pull function also updates a global var that will be used later
echo $f
fi
done | parallel -k pull | tee errors.tmp
IFS=$'\n' ERRORS=($(grep "^GITERROR:" errors.tmp))
rm errors.tmp
for i in "${ERRORS[@]}"; do
echo $i
done
你会看到,即使有4个目录要拉,整个脚本也只需要5秒 - 尽管执行了4批sleep 5
。
答案 2 :(得分:0)
通过添加/列出目录。并行产生一个shell,它与dir相关联。如果git pull失败,则会打印一个魔术字符串。所有输出也保存为out / 1 / *中的副本。完成所有拉动后,检查魔术字符串出现在哪些文件中,并打印出这些命令的STDOUT / STDERR。清理。
parallel --results out 'cd {} && (git pull || echo e_R_r_O_r)' ::: extensions/*/
grep -l e_R_r_O_r out/*/stdout | parallel 'grep -v e_R_r_O_r {//}/stdout; cat {//}/stderr >&2'
rm -r out