为什么直到后台进程结束后函数才返回?


21

考虑以下脚本:

#!/bin/bash
function start {
  leafpad &
  echo $!
}
PID=$(start)
echo "PID is $PID"

该脚本直到叶垫进程结束才继续执行,直到它结束,即使它是后台进程。

为什么是这样?是否可以从功能启动后台进程?

Answers:


22

该函数返回,但是命令替换被阻止,因为您创建了后台作业,但是仍然打开了stdout fd。只需>/dev/null在之前添加即可将其关闭&

#!/bin/bash
function start {
  leafpad >/dev/null &
  echo $!
}
PID=$(start)
echo "PID is $PID"

如果您希望进程也关闭stdin,stdout,stderr,请使用以下命令:

leafpad >/dev/null 0>&1 2>&1 &

这将关闭stdin(0),stdout(1)和stderr(2),然后关闭背景(&)。同样,在使用这些流重定向时,请不要忘记它们是“重复的”,这意味着按执行顺序重复。

1>/dev/null 2>&1

2>&1 1>/dev/null

不一样!在前者中,您将流复制到/ dev / null(这是您想要的),在后者中,您将/ dev / stdout复制到stderr,然后关闭stdout。因此,发送到的任何消息都stderr将出现在您的控制台中。


在我的系统上确认
user120161

10
您没有关闭流,而是对其进行重定向。
dcat

4
关闭 文件描述符n>&-在哪里n
dcat

1
@dcat:是的,但是/dev/null当进程尝试写入其stdout却发现它1是无效的FD 时,重定向到/ from 不会导致i / o错误。因此,帖子中的术语是错误的,而不是实际的bash编程。(实际上,将FD 1复制为0意味着stdin将是使用打开的文件描述符O_RDONLY,当该进程尝试读取时,可能会给出错误(而不是所需的无字节数)。)例如wc >/dev/null 0>&1->wc: standard input: Bad file descriptor
Peter Cordes

1
@PeterCordes-关闭旧描述符并重定向新描述符不需要相互排斥。exec <&- >&- <>/dev/null >&0非常详尽地处理标准输入/输出。zsh至少在设置multios时,它会自动将同一描述符上的所有打开串联在一起的方式有所不同。
mikeserv
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.