Is there a way to make bash job control quiet?
Bash is quite verbose when running jobs in the background:
$ echo toto&
toto
[1] 15922
[1]+ Done echo toto
Since I'm trying to run jobs in parallel and use the output, I'd like to find a way to silence bash. Is there a way to remove this superfluous output?
You can use parentheses to run a background command in a subshell, and that will silence the job control messages. For example:
(sleep 10 & )
Note: The following applies to interactive Bash sessions. In scripts, job-control messages are never printed.
There are 2 basic scenarios for silencing Bash's job-control messages:
Launch-and-forget:
CodeGnome's helpful answer answer suggests enclosing the background command in a simple subshell - e.g, (sleep 10 &)
- which effectively silences job-control messages - both on job creation and on job termination.
This has an important side effect:
-
By using control operator
&
inside the subshell, you lose control of the background job -jobs
won't list it, and neither%%
(the spec. (ID) of the most recently launched job) nor$!
(the PID of the (last) process launched (as part of) the most recent job) will reflect it.[1]
For launch-and-forget scenarios, this is not a problem:
- You just fire off the background job,
- and you let it finish on its own (and you trust that it runs correctly).
[1] Conceivably, you could go looking for the process yourself, by searching running processes for ones matching its command line, but that is cumbersome and not easy to make robust.
Launch-and-control-later:
If you want to remain in control of the job, so that you can later:
- kill it, if need be.
- synchronously wait (at some later point) for its completion,
a different approach is needed:
-
Silencing the creation job-control messages is handled below, but in order to silence the termination job-control messages categorically, you must turn the job-control shell option OFF:
-
set +m
(set -m
turns it back on) -
Caveat: This is a global setting that has a number of important side effects, notably:
- Stdin for background commands is then
/dev/null
rather than the current shell's. - The keyboard shortcuts for suspending (Ctrl-Z) and delay-suspending (Ctrl-Y) a foreground command are disabled.
- For the full story, see
man bash
and (case-insensitively) search for occurrences of "job control".
- Stdin for background commands is then
-
-
To silence the creation job-control messages, enclose the background command in a group command and redirect the latter's stderr output to
/dev/null
{ sleep 5 & } 2>/dev/null
The following example shows how to quietly launch a background job while retaining control of the job in principle.
$ set +m; { sleep 5 & } 2>/dev/null # turn job-control option off and launch quietly
$ jobs # shows the job just launched; it will complete quietly due to set +m
If you do not want to turn off the job-control option (set +m
), the only way to silence the termination job-control message is to either kill
the job or wait
for it:
Caveat: There are two edge cases where this technique still produces output:
- If the background command tries to read from stdin right away.
- If the background command terminates right away.
To launch the job quietly (as above, but without set +m
):
$ { sleep 5 & } 2>/dev/null
To wait
for it quietly:
$ wait %% 2>/dev/null # use of %% is optional here
To kill
it quietly:
{ kill %% && wait; } 2>/dev/null
The additional wait
is necessary to make the termination job-control message that is normally displayed asynchronously by Bash (at the time of actual process termination, shortly after the kill) a synchronous output from wait
, which then allows silencing.
But, as stated, if the job completes by itself, a job-control message will still be displayed.
Wrap it in a dummy script:
quiet.sh:
#!/bin/bash
$@ &
then call it, passing your command to it as an argument:
./quiet.sh echo toto
You may need to play with quotes depending on your input.