Bash,如何让某些后台进程运行但等待其他进程?


11

我有(又)其他wait&&&控制流的问题..

假设我有一个类似这样的脚本,我想在同一时间做更多的工作:

# may take some hours
something InputA > IrrelevantA &
something InputB > IrrelevantB &

# may take an hour
(
   somethingElse InputA > OutputA &
   somethingElse InputB > OutputB &
)&& combine OutputA OutputB > Result

...morestuff

问题1:在脚本中,是否在两个进程继续执行的同时combine等待两个somethingElse进程完成something

问题2:如果不是-我怀疑不是-我如何combine只等待两个somethingElse进程,而something上述进程仍在后台继续工作?

Answers:


13

在您的示例中,combine命令将在子shell退出后立即运行(并提供了最后的后台进程已启动且没有错误)。由于没有wait命令,子shell将在作业启动后立即退出。

如果要基于两个或多个同时后台进程的返回值执行命令,那么除了将临时文件用作返回值之外,我看不到其他任何方法。这是因为wait只能返回其等待的进程之一的返回值。同样,由于后台进程必须在子shell中运行才能获得其返回值,因此它们不能存储在变量中。您可以这样做:

something InputA >IrrelevantA &
something InputB >IrrelevantB &

tmp1=$(mktemp)
tmp2=$(mktemp)

( somethingElse InputA >OutputA; echo $? >"$tmp1" ) &
proc1=$!

( somethingElse InputB >OutputB; echo $? >"$tmp2" ) &
proc2=$!

wait "$proc1" "$proc2"

read ret1 <"$tmp1"
read ret2 <"$tmp2"
[ "$ret1" = 0 && "ret2" = 0 ] && combine OutputA OutputB >Result

rm "$tmp1" "$tmp2"

如果您不太在意返回值,则可以正常启动作业并使用wait

something InputA >IrrelevantA &
something InputB >IrrelevantB &

somethingElse InputA >OutputA &
proc1=$!

somethingElse InputB >OutputB &
proc2=$!

wait "$proc1" "$proc2"
combine OutputA OutputB >Result

嗨,我认为第二个选项对我
Stephen Henderson 2014年

3

进程替换会更有效,特别是如果您不需要保存文件OutputAOutputB,而仅在乎的话Result?这是否会特别节省时间,因为如果您在写入磁盘时I / O速度较慢,那么保存文件OutputAOutputB可能是限速步骤?

combine  <(somethingElse InputA)  <(somethingElse InputB)  >  Result

进程替换使您可以将命令放入内部,<(..here..)而不是将输出保存到文件中,然后在“组合”步骤中将其作为输入读取。

如果记忆是一个限制,规模outputAoutputB超过什么内存可容纳的,它会毁掉整个目的是什么?

是否会combine等到两个进程都完成才开始运行?


这不是“ Jeopardy”;请不要语在一个问题的回应表单。认真地说,您想出了一个新主意,我认为这非常好。回答您的几点:combine将在两个somethingElse命令启动后立即开始运行,但这没关系,因为这些<(…)都是管道。因此combine,如果数据超出了somethingElse流程,将只会被迫等待数据。而且,因为它们是管道,所以尺寸不是问题。…(续)
G-Man说'Resstate Monica''15

(续)…我对您的回答的唯一实质性问题是它不允许测试somethingElse流程的退出状态–尚不清楚这对申请者是否重要。但是,答案也不应该是这样的问题。
G-Man说'恢复莫妮卡'

2

您可以使用以下wait命令:

(echo starting & sleep 10 & wait) && echo done

您可以立即看到“开始”行,“完成”等待10秒钟。


通常,等待需要相同shell的子进程。那里的等待非常棘手。
mikeserv

1
@mikeserv,您在说什么?关键是:它等待该子shell中的所有子级。
psusi 2014年

通过我的初步测试,这是可行的。我现在将在大型脚本上进行尝试
Stephen Henderson 2014年

恰好-同一外壳的子级 - 外壳。它应适用于任何不尝试转义的进程-或守护进程或其他任何进程。这就是我的全部意思-只要您的流程尊重流程负责人,就可以等待,但是一旦流程尝试成为自己的流程负责人,等待就会出现问题。
mikeserv

0

我实际上在这里的另一个答案中演示了如何完成这种事情。答案是关于确保后台进程维护2个日志的问题,所以我用10个示例进行了演示。

演示脚本

cat <<-\DEMO >|${s=/tmp/script} 
printf 'tty is %s\nparent pid is %s\npid is pid=%s\n' \
     "$(tty)" "$PPID" "$$"
exec 1>&2 ; nums=$(seq 0 9)
rm ${files=$(printf "/tmp/file%s\n" $nums)}
for n in $nums ; do { for f in $files ; do
    echo "Line $n" >>"$f" ; done
sleep 1 ; } ; done
#END
DEMO

运行演示

s=/tmp/script ;chmod +x $s ;info="$(($s &)2>&- &)"
echo "$info" ; pid="${info##*=}" ; echo
while ps -p $pid >/dev/null ; do sleep 3 ; done
for f in /tmp/file[0-9] ; do
    printf 'path : %s\tline count : %s\n' \
        $f $(<$f wc -l)
done

输出:

tty is not a tty
parent pid is 1
pid is 12123

path : /tmp/file0    line count : 10
path : /tmp/file1    line count : 10
path : /tmp/file2    line count : 10
path : /tmp/file3    line count : 10
path : /tmp/file4    line count : 10
path : /tmp/file5    line count : 10
path : /tmp/file6    line count : 10
path : /tmp/file7    line count : 10
path : /tmp/file8    line count : 10
path : /tmp/file9    line count : 10

以上说明。它建立并运行一个名为脚本/tmp/script chmod它作为可执行文件,并运行它在&background&backgrounded ( subshell )

该脚本有rms /tmp/file0-910个文件,并且echoes每秒钟一行一行地插入所有10 个文件中。我$info从不知名的流程中捕获了一些内容,并通过我捕获的$(command substitution). While ps静态报告将其呈现出来$pid,我知道它仍在运行,所以我sleep.完成后,所有10个文件中的行都被计入wc.

以这种方式调用流程后,您可以自由关闭其原始父流程,并且该流程将继续执行-实际上已被取消。这也意味着您不能使用常规wait命令,但是在任何情况下等待ps返回都应该更可靠。

我认为,值得一提的是,该过程实际上是最初调用的,$(command substitution)printfs我是$info我想要的,因此我可以有效地控制它。但是,一旦它放弃了其终端输出exec 1>&2(在与相同的子shell中关闭了2>&-),则该过程转义,我不得不在另一端等待它。Kinda兼具两全其美的优势,特别是如果您使用它来处理输入管道,只要您能将所有重定向和流程领导者的思想牢记在心。

其他所有内容仅用于演示。您仅需运行以下脚本即可:

info="$(($script_path &)2>&- &)"    

注意:这仅打印到终端上我想要演示的内容。正如$PPID,该流程所指出的,此过程已被终端拒绝,并且是$PID 1.

如果您想同时运行其中两个并等待它们,则只需交出ps两个pid并等待即可。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.