我目前正在子 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/null
butsleep
的 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
为任何文件。