How could I hide the standard output of a process only when it is running in background?
For example,
test.sh
#!/bin/bash
for i in $(seq 200); do
echo $i
done
Now, I run the script. I stop it. I put it back to test it keeps running. Then I put it on background but it keeps printing in the standard output and I can't keep working. Is there a way to redirect or hide the process output ONLY when it is on background?
dione@saturno:~$ ./test.sh
1
2
3
^Z
[1]+ Detenido ./test.sh
dione@saturno:~$ fg %1
./test.sh
4
5
6
^Z
[1]+ Detenido ./test.sh
dione@saturno:~$ %1 &
[1]+ ./test.sh &
dione@saturno:~$ 7
8
9
10
11
12
13
14
15
fg
./test.sh
16
17
^C
dione@saturno:~$
Redirecting a running process's output is not easy. But there might be alternatives if you work from the start:
With this method, since the
tail
hasSIGSTOP
sent to it, it won't output anything until you explicitly bring it to the foreground usingfg
(or something similar) and until the script has finished. Adjust the1000
to get as many lines as you want.A better alternative might be
grep
:You can signal
SIGCONT
andSIGSTOP
togrep
to start and stop the output as you want.This can probably be combined with the re-attachment of open file descriptors from the SO question linked above (maybe with the script in this answer) so that this can be done with processes already opened.
If buffering is indeed a problem with
grep
, as Volker Siegel points out, then one might consider using a more complex set of commands. First, note thatsort
uses temporary files, so buffering should not be a problem for it. It will act like a combination oftail
andgrep
- waiting until the command is finished, liketail
, and keeping the entire output, likegrep
. Something like:The loss here is that you can't start and stop the output at will, and there's the huge computation expended in an useless
sort
, as well as the work expended in adding and removing the;
.Further tests reveal that Volker is indeed correct:
For a script like (call it
test.sh
):and the command:
the number in
/tmp/log
was stuck at 12768 (with a similar figure for . And with the commandThe script ran to completion (
/tmp/log
had1000000
) without a peep fromsed
.I still haven't managed to integrate this with the GDB method, but this as it is can be made to function as a function, similar to John1024's. The problem is that you have no good way of knowing if the process has ended, since the shell only notifies you if the entire job has ended. So you'll have to use a checking function:
You could wrap the
"$@"
in another function which will notify you once the job is done, using something likenotify-send
orwrite
.It's been a nice exercise, but ultimately the simplest way is to redirect to
/dev/null
and forget the output: How to redirect the output of an application in background to /dev/null.This script redirects stdout to
/dev/null
only if the script is running in the background:The key here is that the
ps
stat
field has a+
in it when the job is foreground. If the+
is missing, we are in background.If you want to keep stdout around for some things but not others, we can create a file descriptor 3 for the discretionary output and keep stdout active for other output. The script below implements this. It sends the loop output to file descriptor 3. File description 3 is either stdout if the job is running in the foreground or
/dev/null
if it is running in the background:A Simple Way to Run Any Command in Background and Silently
Create this bash function:
Then, anytime that you want to a noisy command, say
seq 200
, in background, type:The command will be run in background and its stdout will be disposed of.
To make the definition of
bkg
permanent, place the definition in~/.bashrc
.