仅当进程完成时才显示完整输出

仅当进程完成时才显示完整输出

这是我的脚本:

#! /bin/bash

ret=0
file_out1=$(mktemp)
file_out2=$(mktemp)

(echo first start; sleep 2s; echo first finish;) &> $file_out1 &
ret=$?
P1=$!
(echo second start; sleep 1s; echo second finish;) &> $file_out2 &
ret=$?
P2=$!

wait $P1 $P2 || ret=$?

cat $file_out1
cat $file_out2

exit $ret

这里,输出是:

first start
first finish
second start
second finish

但输出应该是:

second start
second finish
first start
first finish

我的意思是,应该在完成cat $file_out1后立即运行,并且应该在完成后立即运行。P1cat $file_out2P2

而且,我想确保P1成功结束,P2也成功结束。最后,我怎么知道其中是否有错误P1P2两者都有错误。

在此脚本中,$ret无法正常工作(始终如此exit 0)。运行后,很高兴知道它$ret是来自P1还是来自P2。比如说P1有返回码x1,P2有返回码x2。如果存在非零退出代码,则使用非零返回代码退出程序。

更新1:

用 askubuntu 回答,建议我们可以使用--group并行命令的参数来确保每个命令的输出等待命令完成(避免混合输出)。

它显示的命令是parallel --group 'echo -n {};sleep {};echo {}' ::: 1 3 2 4.

该命令在我的机器上有效。但是,我不明白如何在我的上下文中使用此命令。

我的意思是我怎样才能得到

second start
second finish
first start
first finish

当输入命令是echo first start; sleep 2s; echo first finish;echo second start; sleep 1s; echo second finish;使用gnu并行时。

更新2:

我目前所在的代码是:

#! /bin/bash

function first {
    echo first start
    sleep 2s
    echo first finish
}
function second {
    echo second start
    sleep 1s
    echo second finish
}

export -f first && export -f second

parallel -j2 ::: first second

这实际上解决了我的问题。

答案1

我想您希望每个任务在终止时立即显示输出,但避免折叠它们的输出,这就是为什么您将其缓冲在文件中 - 没关系,您也可以在输出前加上 sed 前缀,让它在出现时流动,然后根据需要再次排序:这是为了防止数据量不可预测和存储溢出的风险。

你的错误:

  • 当您使用 fork 后台进程时&,您将无法访问其最终状态(您所期望的ret=$?是其他内容)
  • 当您等待它们完成时,您无法预测哪一个将首先终止,以及您是否会wait按时捕获每个进程的最终状态:在进程终止后为时已晚,即使该进程的最终状态是,wait也会得到。这是不可预测的。1270

您的愿望是获得与顺序运行相同的反馈,但具有并行性的持续时间优势,并最大限度地减少酱汁。

让它们在自己的框中执行,管理输出竞争 -flock文件描述符是干净的 - 并强制它们在某处记录其最终状态 - 再次,文件描述符是干净的。

编辑正如 @AhmadIsmail 编辑所说,GNU 并行是一体化解决方案。无论如何,就让这个吧。

#!/bin/bash
# wrap background
mybackground(){
 tmp=$(mktemp) && trap "rm -f $tmp" RETURN
 exec {safe1}>&1 {safe2}>&2 1>$tmp 2>$tmp # swap descriptors
 (eval $@) # work
 echo $? >&$fdstatus # report status 
 exec >&$safe1 2>&$safe2 # restore descriptors
 flock 1 cat $tmp # report output
}
(
mybackground "echo first start; sleep 2s; echo first finish;exit 2" &
mybackground "echo second start; sleep 1s; echo second finish" &
) {fdstatus}> >(
  while read rc;do ((sum+=rc));done;echo sum=$sum;exit $sum ## collect & sum status
) | cat # wait {fdstatus} termination

相关内容