在后台执行进程,不打印"完成",并获取PID

joz*_*yqk 7 bash

这似乎是一件非常微不足道的事情,但我很困难.

要在后台执行某些操作,请使用&:

>>> sleep 5 &
[1] 21763
>>> #hit enter
[1]+  Done                    sleep 5
Run Code Online (Sandbox Code Playgroud)

但有一个.bashrc的来源背景脚本输出作业信息是非常令人沮丧的,所以你可以做这个来解决它:

>>> (sleep 5 &)
Run Code Online (Sandbox Code Playgroud)

好的,所以现在我想获得sleepfor wait或的PID kill.不幸的是它在子shell中运行所以典型的$!方法不起作用:

>>> echo $!
21763
>>> (sleep 5 &)
>>> echo $!
21763 #hasn't changed
Run Code Online (Sandbox Code Playgroud)

所以我想,也许我可以通过这种方式获得子shell来打印它的PID:

>>> sleep 5 & echo $!
[1] 21803 #annoying job-start message (stderr)
21803 #from the echo
Run Code Online (Sandbox Code Playgroud)

但是现在当我在子shell中抛出它时,无论我如何尝试捕获子shell的stdout,它似乎都会阻塞直到sleep完成.

>>> pid=$(sleep 5 & echo $!)
Run Code Online (Sandbox Code Playgroud)

如何在后台运行某些内容,获取其PID并停止打印作业信息和" Done"?

kon*_*box 5

解决方案A.

召唤进程时,将shell的stderr重定向到>/dev/null该召唤实例.我们可以通过复制fd 2来做到这一点,这样我们仍然可以使用重复的fd进行处理.我们在一个块中执行所有这些操作以使重定向临时:

{ sleep 5 2>&3 & pid=$!; } 3>&2 2>/dev/null
Run Code Online (Sandbox Code Playgroud)

现在为了防止以后显示"完成"消息,我们从作业表中排除了该过程,这是通过以下disown命令完成的:

{ sleep 5 2>&3 & disown; pid=$!; } 3>&2 2>/dev/null
Run Code Online (Sandbox Code Playgroud)

如果未启用作业控制则没有必要.可以使用set +m或禁用作业控制shopt -u -o monitor.

解决方案B.

我们也可以使用命令替换来召唤进程.我们唯一的问题是进程仍然将自己挂钩到$()读取stdout 创建的管道,但我们可以通过在它之前复制原始stdout然后使用该文件描述符来解决这个问题:

{ pid=$( sleep 200s >&3 & echo $! ); } 3>&1
Run Code Online (Sandbox Code Playgroud)

如果我们将进程的输出重定向到某个地方,则可能没有必要/dev/null:

pid=$( sleep 200s >/dev/null & echo $! )
Run Code Online (Sandbox Code Playgroud)

与流程替换类似:

{ read pid < <(sleep 200s >&3 & echo $!); } 3>&1
Run Code Online (Sandbox Code Playgroud)

有些人可能会说重定向不是必需的,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.
Run Code Online (Sandbox Code Playgroud)
  • 您可以选择创建一个永久复制的fd,exec 3>&1这样您就可以pid=$( sleep 200s >&3 & echo $! )在下一行中使用.