You can use the command wait PID
to wait for a process to end.
You can also retrieve the PID of the last command with $!
In your case, something like this would work:
command1 & #run command1 in background
PID=$! #catch the last PID, here from command1
command2 #run command2 while command1 is running in background
wait $PID #wait for command1, in background, to end
command3 #execute once command1 ended
Following your edit, as you have multiple PIDs and you know them, you can do that:
command1 & #run command1 in background
PID1=xxxxx
PID2=yyyyy
PID3=xxyyy
PID4=yyxxx
command2 #run command2 while command1 is running in background
wait $PID1 $PID2 $PID3 $PID4 #wait for the four processes of command1, in background, to end
command3 #execute once command1 ended
I've located a number of similar topics to this one that consider using such things as xdotool and wmctl for the purpose of testing the launch of a persistent windowed application or other persistent sub-process. But using these seems like an unnecessary complication. The solution below would permit conditional execution of a persistent sub-process. It utilizes a sleep duration of half a second. If the sub-process of interest were to require longer to successfully launch then this duration would need to be increased accordingly.
Bash source file launch
#/usr/bin/env bash
# launch : will allow launching a windowed application or persistent
# sub-process in the background so that conditional execution can be
# applied to determine whether or not it has launched successfully -
# dependencies: GNU coreutils (sleep), util-Linux (kill)
# usage: ./launch process arg_1 .. arg_n && echo TRUE || echo FALSE
$@ &>/dev/null & sleep 0.5 && kill -0 $! 2>/dev/null
# end file
So that:
$ ./launch mupdf example.pdf && echo TRUE || echo FALSE
TRUE
$ ./launch mupdf nofile.pdf && echo TRUE || echo FALSE
FALSE
As a postcript to this information, I thought it would be useful to include the advice of mikeserv in the comments to the opening post.
Whereas the above construct accomplishes the immediate task, mikeserv points out that it could lead to other problems in that it does not propagate the signal to the calling script; it instead ignores and discards it. This is a very important observation.
Signals are a key element of interprocess communication, and can lead to the possibility of event driven scripts. So for more robust and effective scripts, mikeserv suggests the following to catch the signal so that it can be propagated:
{ mupdf some.pdf || kill -"$(($?&127))" "$$"; } &
where $?&127
permits actioning 1 to 128 possible signals (POSIX), my Debian system has 64, so the signal mask could be $?&63
instead.
So as a concluding remark, for very simple scripts, where interprocess communication is not of interest, the proposed launch can be useful, but for anything more, especially where interprocess communication is important, capture (and propagate) the signal, as advised by mikeserv.
Best Answer
In your example the
combine
command will just be run as soon as the subshell exits (and provided the last background process was started without an error). The subshell will exit immediately after the jobs are started since there is nowait
command.If you want to execute a command based on the return value of two or more simultaneous background processes, then I can't see any other way other than to use temporary files for the return values. This is because
wait
can only return the return value of one of the processes it waits for. Also since the background processes must be run in subshells to get their return values at all, they cannnot be stored in variables. You could do:If you don't really care about the return values, you can just start the jobs normally and use
wait
: