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".
  • 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.