所以我有一个while循环,循环遍历包含名称的文本文件,然后在列表上执行后台进程。这一切都很好,但是当它结束时,我需要ctrl-c。完成所有过程后如何执行SIGINT,所以我不需要ctrl-c?
我是否需要在每个流程中执行此操作?或者我可以通过使用像睡眠这样的东西在循环中做到这一点吗?
这是我目前所拥有的,但不太有用。
while read BAR; do foo $BAR & done < bars.txt; pid=$!; wait; kill pid
答案 0 :(得分:1)
现在您只收集最后 PID,而不是所有后台进程的PID。
如果您收集PID,您可以单独等待它们 - 这可以让您检查各个作业是否失败,或以查看它们中的哪一个未实际完成:< / p>
pids=( )
while read bar; do
foo "$bar" & pids+=( "$!" )
done < bars.txt
for pid in "${pids[@]}"; do
echo "Checking exit status of $pid..."
if wait "$pid"; then
echo "$pid succeeded!"
else
echo "$pid failed!"
fi
done
如果您想要追踪哪些特定值处理成功或失败,您可以做得更好(使用bash 4.0或更高版本):
declare -A pids=( )
while read -r bar; do
foo "$bar" & pids[$!]="$bar"
done < bars.txt
for pid in "${!pids[@]}"; do
bar=${pids[$pid]}
echo "Checking exit status of $pid (processing value $bar)..."
if wait "$pid"; then
echo "$pid (for $bar) succeeded!"
else
echo "$pid (for $bar) failed!"
fi
done
在上述任何一种情况下,wait
的每次调用都负责在相应的PID退出后返回。因此,当所有后台任务都退出时,您的脚本将自行退出。
最后,要强制您的孩子退出,您可以构建一个利用PID列表的信号处理程序:
shutdown() { kill "${pids[@]}"; } # or "${!pids[@]}" for the second example
trap shutdown 0
答案 1 :(得分:1)
使用GNU Parallel,它看起来像这样:
parallel -j0 foo {} < bars.txt
echo $? jobs failed
如果省略-j0
,它将为每个CPU核心运行一个作业。
如果您需要确切知道哪些作业失败,您可以使用作业日志:
parallel --joblog jl -j0 foo {} < bars.txt
cat jl
它还确保不同作业的输出不会混合在一起,因此如果您使用输出,则可以保证您不会从两个不同的作业中获得半个行。
GNU Parallel是一个通用的并行程序,可以很容易地在同一台机器上或在你有ssh访问权限的多台机器上并行运行作业。
如果要在4个CPU上运行32个不同的作业,并行化的直接方法是在每个CPU上运行8个作业:
GNU Parallel会在完成后生成一个新进程 - 保持CPU处于活动状态,从而节省时间:
<强>安装强>
您应该使用软件包管理器安装GNU Parallel,但如果没有为您的发行版打包GNU Parallel,则可以进行个人安装,不需要root访问权限。这可以在10秒内完成:
(wget -O - pi.dk/3 || curl pi.dk/3/ || fetch -o - http://pi.dk/3) | bash
有关其他安装选项,请参阅http://git.savannah.gnu.org/cgit/parallel.git/tree/README
了解详情
查看更多示例:http://www.gnu.org/software/parallel/man.html
观看介绍视频:https://www.youtube.com/playlist?list=PL284C9FF2488BC6D1
完成教程:http://www.gnu.org/software/parallel/parallel_tutorial.html
注册电子邮件列表以获得支持:https://lists.gnu.org/mailman/listinfo/parallel
答案 2 :(得分:0)
如果你真的想要一个单行,你可以围绕以下逻辑构建它(为了更好的可读性而格式化)。
while -r read BAR
do
foo "$BAR" &
done < bars.txt
wait
这将等待所有后台任务完成(包括执行此命令之前启动的任何后台任务)。这有点粗糙(CharlesDuffy已经提出了一个允许更好地跟踪任务的解决方案),但它具有足够短的单线程的可疑优势。
while -r read BAR ; do foo "$BAR" & done < bars.txt ; wait
要在启动它们之后立即杀死它们(我不确定你为什么要这样做),你可以这样做:
while -r read BAR ; do foo "$BAR" & done < bars.txt ; kill $(jobs -p)
再一次,这将发出所有后台工作的信号,而不仅仅是您刚刚推出的工作。