将 Subshel​​l 后台进程 pid 分配给变量

将 Subshel​​l 后台进程 pid 分配给变量

我目前正在子 shell 中启动后台进程,想知道如何将其 pid 号分配给子 shell 范围之外的变量?
我尝试了很多不同的方法,但MYPID始终保持不变0

MYPID = 0;
({ sleep 2 & }; $MYPID=$!)
({ sleep 2 & }; echo $!) > $MYPID

它返回值的唯一方法是:

$MYPID=$({ sleep 2 & }; echo $!)

然而,这会丢弃后台处理指令,并且只会在 2 秒后返回结果。

答案1

bash非交互时不应打印作业状态。

如果这确实是交互式的bash,你可以这样做:

{ pid=$(sleep 20 >&3 3>&- & echo "$!"); } 3>&1

我们希望sleep的 stdout 转到之前的位置,而不是提供变量的管道$pid。所以我们保存文件描述符 3 ( 3>&1) 中的 stdout 并将其恢复为sleep内部命令替换。因此pid=$(...)一旦echo终止就返回,因为没有任何打开的文件描述符存在到供给 的管道中$pid

但请注意,因为它是从子 shell 启动的(此处是命令替换),所以它sleep不会在单独的进程组中运行。因此,它sleep 20 &与例如终端 I/O 方面的运行不同。

也许更好的方法是使用支持生成的 shell不承认的后台工作,例如zsh您可以做的事情:

sleep 20 &! pid=$!

使用bash,您可以用以下方法近似它:

{ sleep 20 2>&3 3>&- & } 3>&2 2> /dev/null; pid=$!; disown "$pid"

bash输出[1] 21578到 stderr。因此,我们再次在重定向到 /dev/null 之前保存 stderr,并为sleep命令恢复它。这样,[1] 21578转到/dev/nullbutsleep的 stderr 就会像往常一样进行。

如果您要将所有内容重定向到 /dev/null,那么您只需执行以下操作:

{ apt-get update & } > /dev/null 2>&1; pid=$!; disown "$pid"

仅重定向标准输出:

{ apt-get-update 2>&3 3>&- & } 3>&2 > /dev/null 2>&1; pid=$!; disown "$pid"

答案2

第二行无法工作

({ sleep 2 & }; $MYPID=$!)

fork( ... )一个子 shell,设置 MYPID,然后子 shell 退出,它的值就会丢失。

第三行也不起作用

({ sleep 2 & }; echo $!) > $MYPID

你只需回显 $!到本地目录上名为 0 的文件。

我可以提供的唯一答案是通过临时文件(因为 var 无法被推回)

 ( { sleep 100 & } ; echo $! > u ) > /dev/null &> /dev/null
 MYPID=$(<u)

您可以替换u为任何文件。

相关内容