这似乎是一件非常微不足道的事情,但我很困惑。
要在后台执行某些操作,请使用&
:
>>> sleep 5 &
[1] 21763
>>> #hit enter
[1]+ Done sleep 5
但是使用bashrc源代码后台脚本输出作业信息非常令人沮丧,因此您可以this进行修复:
>>> (sleep 5 &)
好的,现在我想获得sleep
或wait
的{{1}}的PID。不幸的是,它在子shell中运行,因此典型的kill
方法不起作用:
$!
所以我想,也许我可以通过这种方式让子shell打印它的PID:
>>> echo $!
21763
>>> (sleep 5 &)
>>> echo $!
21763 #hasn't changed
但是现在当我在子shell中抛出它时,无论我如何尝试捕获子shell的stdout,它似乎都会阻塞,直到>>> sleep 5 & echo $!
[1] 21803 #annoying job-start message (stderr)
21803 #from the echo
完成。
sleep
如何在后台运行某些内容,获取其PID并停止打印作业信息" >>> pid=$(sleep 5 & echo $!)
"?
答案 0 :(得分:5)
召唤进程时,将shell的stderr重定向到>/dev/null
以获取该召唤实例。我们可以通过复制fd 2来做到这一点,这样我们仍然可以使用重复的fd进行处理。我们在一个块中完成所有这些操作以使重定向成为临时的:
{ sleep 5 2>&3 & pid=$!; } 3>&2 2>/dev/null
现在要防止"完成"稍后显示的消息,我们从作业表中排除了该过程,这是通过disown
命令完成的:
{ sleep 5 2>&3 & disown; pid=$!; } 3>&2 2>/dev/null
如果未启用作业控制,则不需要。可以使用set +m
或shopt -u -o monitor
停用作业控制。
我们也可以使用命令替换来召唤进程。我们遇到的唯一问题是进程仍然将自己挂钩到由$()
创建的读取stdout的管道,但我们可以通过在它之前复制原始stdout然后使用该文件描述符来解决这个问题:
{ pid=$( sleep 200s >&3 & echo $! ); } 3>&1
如果我们重定向流程可能没有必要。输出像/dev/null
:
pid=$( sleep 200s >/dev/null & echo $! )
与流程替换类似:
{ read pid < <(sleep 200s >&3 & echo $!); } 3>&1
有些人可能会说process substitution
不需要重定向,但问题是可能访问其stdout
的进程会很快死亡。例如:
$ function x { for A in {1..100}; do echo "$A"; sleep 1s; done }
$ read pid < <(x & echo $!)
$ kill -s 0 "$pid" &>/dev/null && echo "Process active." || echo "Process died."
Process died.
$ read pid < <(x > /dev/null & echo $!)
$ kill -s 0 "$pid" &>/dev/null && echo "Process active." || echo "Process died."
Process active.
exec 3>&1
创建一个永久性重复的fd,这样您就可以在下一行中使用pid=$( sleep 200s >&3 & echo $! )
。答案 1 :(得分:4)
您可以使用read
公告来捕获输出:
read -r pid < <(sleep 10 & echo $!)
然后:
ps -p $pid
PID TTY TIME CMD
78541 ttys001 0:00.00 sleep 10
答案 2 :(得分:2)
试试这个:
pid=$((sleep 5 & echo $!) | sed 1q)
答案 3 :(得分:2)
bash中的set +m
禁用监控模式。换句话说,它消除了令人讨厌的Done
消息。
要再次启用,请使用set -m
。
例如:
$ set +m
$ (sleep 5; echo some) &
[1] 23545 #still prints the job number
#after 5 secs
some
$ #no Done message...
答案 4 :(得分:0)
我找到了一个好方法,不需要子shell,将保持父子关系。
自:[1] 21763
和[1]+ Done sleep 5
都是stderr,即&2
。
我们可以将&2
重定向到/dev/null
,这里是代码:
exec 7>&2 2>/dev/null # Here backup 2 to 7, and redirect 2 to /dev/null
sleep 5
wait
exec 2>&7 7>&- # here restore 7 to 2, and delete 7.
请参阅:Using exec