Bash is quite verbose when running jobs in the background:
$ echo toto&
toto
[1] 15922
[1]+ Done echo toto
Since I\
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:
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:
&
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:
[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.
If you want to remain in control of the job, so that you can later:
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)/dev/null
rather than the current shell's.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:
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.
Interactively, no. It will always display job status. You can influence when the status is shown using set -b
.
There's nothing preventing you from using the output of your commands (via pipes, or storing it variables, etc). The job status is sent to the controlling terminal by the shell and doesn't mix with other I/O. If you're doing something complex with jobs, the solution is to write a separate script.
The job messages are only really a problem if you have, say, functions in your bashrc which make use of job control which you want to have direct access to your interactive environment. Unfortunately there's nothing you can do about it.
One solution (in bash anyway) is to route all the output to /dev/null
echo 'hello world' > /dev/null &
The above will not give you any output other than the id for the bg process.
You can use parentheses to run a background command in a subshell, and that will silence the job control messages. For example:
(sleep 10 & )
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.