在后台运行 bash 命令而不打印作业和进程 ID

在 bash 的后台运行一个进程是相当容易的。

$ echo "Hello I'm a background task" &
[1] 2076
Hello I'm a background task
[1]+  Done                    echo "Hello I'm a background task"

但是输出是冗长的。在第一行输出作业 id 和后台任务的进程 id,然后输出命令,最后输出作业 id 及其状态和触发作业的命令。

有没有一种方法可以抑制运行后台任务的输出,使输出看起来与结尾没有与号的输出完全一样?例如:

$ echo "Hello I'm a background task" &
Hello I'm a background task

我这样问的原因是,我想运行一个后台进程作为制表符完成命令的一部分,因此该命令的输出必须是不间断的才有意义。

44009 次浏览

In some newer versions of bash and in ksh93 you can surround it with a sub-shell or process group (i.e. { ... }).

/home/shellter $ { echo "Hello I'm a background task" & } 2>/dev/null
Hello I'm a background task
/home/shellter $

Not related to completion, but you could supress that output by putting the call in a subshell:

(echo "Hello I'm a background task" &)

Building off of @shellter's answer, this worked for me:

tyler@Tyler-Linux:~$ { echo "Hello I'm a background task" & disown; } 2>/dev/null; sleep .1;
Hello I'm a background task
tyler@Tyler-Linux:~$

I don't know the reasoning behind this, but I remembered from an old post that disown prevents bash from outputting the process ids.

Building on the above answer, if you need to allow stderr to come through from the command:

f() { echo "Hello I'm a background task" >&2; }
{ f 2>&3 &} 3>&2 2>/dev/null

Try:

user@host:~$ read < <( echo "Hello I'm a background task" & echo $! )
user@host:~$ echo $REPLY
28677

And you have hidden both the output and the PID. Note that you can still retrieve the PID from $REPLY

Sorry for the response to an old post, but I figure this is useful to others, and it's the first response on Google.

I was having an issue with this method (subshells) and using 'wait'. However, as I was running it inside a function, I was able to do this:

function a {
echo "I'm background task $1"
sleep 5
}


function b {
for i in {1..10}; do
a $i &
done
wait
} 2>/dev/null

And when I run it:

$ b
I'm background task 1
I'm background task 3
I'm background task 2
I'm background task 4
I'm background task 6
I'm background task 7
I'm background task 5
I'm background task 9
I'm background task 8
I'm background task 10

And there's a delay of 5 seconds before I get my prompt back.

The subshell solution works, but I also wanted to be able to wait on the background jobs (and not have the "Done" message at the end). $! from a subshell is not "waitable" in the current interactive shell. The only solution that worked for me was to use my own wait function, which is very simple:

myWait() {
while true; do
sleep 1; STOP=1
for p in $*; do
ps -p $p >/dev/null && STOP=0 && break
done
((STOP==1)) && return 0
done
}


i=0
((i++)); p[$i]=$(do_whatever1 & echo $!)
((i++)); p[$i]=$(do_whatever2 & echo $!)
..
myWait ${p[*]}

Easy enough.

Based on this answer, I came up with the more concise and correct:

silent_background() {
{ 2>&3 "$@"& } 3>&2 2>/dev/null
disown &>/dev/null  # Prevent whine if job has already completed
}
silent_background date