7

I have a script with

for i in 1 2 3 4; do
    do_something $i &
done

And when I call it, it terminates before all do_something terminated. I found this question with many different answers.

Edit: help wait tells me that

If ID is not given, waits for all currently active child processes, and the return status is zero.

Is it not sufficient to just add a single wait at the end?

fabian789
  • 217
  • 2
  • 8
  • 1
    No you need to wait for each of the process to complete. There is an answer suggesting how to wait for all the bg processes in your link – Inian Sep 12 '19 at 07:08
  • What is your question? `wait` is a shell builtin. [Use `help wait` instead of `man wait`](https://unix.stackexchange.com/questions/167004/why-dont-shell-builtins-have-proper-man-pages) – pLumo Sep 12 '19 at 07:08
  • @pLumo See edit – fabian789 Sep 12 '19 at 07:10
  • 1
    Why don't you just try? E.g. `for i in 1 2 3 4; do sleep $i & done; wait`. Spoiler: Yes it is sufficient. – pLumo Sep 12 '19 at 07:10
  • @pLumo Because it's critical that it work for the real world use case and I would rather rely on knowledge than a single example :) – fabian789 Sep 12 '19 at 07:13
  • anyways, you might want to use `parallel do_something ::: 1 2 3 4;` – pLumo Sep 12 '19 at 07:15
  • 4
    Notice that wait only works with _direct_ children of your script. If you use `(do_something $i &)` (ie in a subshell) your `wait` will not wait for it, because the actual `do_something` process will be reparented to pid 1 (init). –  Sep 12 '19 at 07:25

2 Answers2

13

Yes, it's enough to use a single wait with no arguments at the end to wait for all background jobs to terminate.

Note that background jobs started in a subshell would need to be waited for in the same subshell that they were started in. You have no instance of this in the code that you show.

Note also that the question that you link to asks about checking the exit status of the background jobs. This would require wait to be run once for each background job (with the PID of that job as an argument).

Kusalananda
  • 320,670
  • 36
  • 633
  • 936
  • This did not work for me. A single line of `wait` at the end with no parameters, did not help me. I loop over git repositories and pull them. Coming from [this](https://unix.stackexchange.com/questions/687979/how-to-know-all-subshells-are-executed-and-finished) question. – Saeed Neamati Jan 26 '22 at 11:50
  • @SaeedNeamati That question and the question linked to in the question above both start background jobs in a subshell but call `wait` outside that subshell. – Kusalananda Aug 13 '22 at 09:50
-1

In my opinion, even though a single wait without parameters should be sufficient, this is not a good practice (relay on a default behaviour). I would collect the pid returned from each call, and wait for these pids explicitly.

Eran Ben-Natan
  • 568
  • 2
  • 7
  • 6
    Why would relying on default behaviour be bad practice? The `wait` command is [a standard command](https://pubs.opengroup.org/onlinepubs/9699919799.2018edition/utilities/wait.html) with well defined semantics. – Kusalananda Sep 12 '19 at 09:11
  • This answer would be seriously improved if it included any reasons for `wait` without arguments being not a good practice. – Neinstein Aug 16 '23 at 12:45