zan*_*ona 5 shell bash subshell variable
我目前正在子 shell 中启动后台进程,想知道如何将其 pid 编号分配给子 shell 范围之外的变量?
我尝试了许多不同的方法,但MYPID始终设置为0.
MYPID = 0;
({ sleep 2 & }; $MYPID=$!)
({ sleep 2 & }; echo $!) > $MYPID
Run Code Online (Sandbox Code Playgroud)
它返回值的唯一方法是:
$MYPID=$({ sleep 2 & }; echo $!)
Run Code Online (Sandbox Code Playgroud)
然而,这会丢弃后台进程指令,它只会在 2 秒后返回结果。
bash 非交互式时不应打印作业状态。
如果这确实是交互式的bash,你可以这样做:
{ pid=$(sleep 20 >&3 3>&- & echo "$!"); } 3>&1
Run Code Online (Sandbox Code Playgroud)
我们希望sleep的 stdout 转到它之前的位置,而不是提供$pid变量的管道。因此,我们将外部标准输出保存在文件描述符 3 ( 3>&1) 中,并sleep在命令替换内部恢复它。所以pid=$(...)一旦echo终止就返回,因为没有任何东西留下一个打开的文件描述符到 feed 的管道$pid。
但是请注意,因为它是从子shell(此处为命令替换)启动的,因此sleep不会在单独的进程组中运行。因此sleep 20 &,例如,就终端的 I/O 而言,它与运行不同。
也许更好的是使用一个支持生成被否认的后台作业的外壳,比如zsh你可以做的:
sleep 20 &! pid=$!
Run Code Online (Sandbox Code Playgroud)
使用bash,您可以将其近似为:
{ sleep 20 2>&3 3>&- & } 3>&2 2> /dev/null; pid=$!; disown "$pid"
Run Code Online (Sandbox Code Playgroud)
bash输出[1] 21578到标准错误。同样,我们在重定向到 /dev/null 之前保存 stderr,并为sleep命令恢复它。这样,[1] 21578转到/dev/nullbutsleep的 stderr 会像往常一样。
如果您无论如何都要将所有内容重定向到 /dev/null ,您可以简单地执行以下操作:
{ apt-get update & } > /dev/null 2>&1; pid=$!; disown "$pid"
Run Code Online (Sandbox Code Playgroud)
仅重定向标准输出:
{ apt-get-update 2>&3 3>&- & } 3>&2 > /dev/null 2>&1; pid=$!; disown "$pid"
Run Code Online (Sandbox Code Playgroud)