我注意到使用Start()
创建的子进程将在程序退出后终止,例如:
package main
import "os/exec"
func main() {
cmd := exec.Command("sh", "test.sh")
cmd.Start()
}
当main()
退出时,test.sh
将停止运行
答案 0 :(得分:2)
子流程应该在流程结束后继续运行,只要它干净地结束,如果你点击^C
就不会发生。
您可以做的是拦截发送到您的流程的信号,以便您可以干净利落地结束。
sigchan := make(chan os.Signal, 1)
signal.Notify(sigchan,
syscall.SIGINT,
syscall.SIGKILL,
syscall.SIGTERM,
syscall.SIGQUIT)
go func() {
s := <-sigchan
// do anything you need to end program cleanly
}()
答案 1 :(得分:1)
尝试修改程序a以使用Run而不是start。通过这种方式,Go程序将在退出之前等待sh脚本完成。
package main
import (
"log"
"os/exec"
)
func main() {
cmd := exec.Command("sh", "test.sh")
err := cmd.Run()
if err != nil {
log.Fatalln(err)
}
}
同样地,你总是可以使用一个等待小组,但我认为这样做太过分了。
你也可以只做一个有或没有等待组的例程。取决于你是否想要等待程序sh程序完成
package main
import (
"os/exec"
)
func runOffMainProgram() {
cmd := exec.Command("sh", "test.sh")
cmd.Start()
}
func main() {
// This will start a go routine, but without a waitgroup this program will exit as soon as it runs
// regardless the sh program will be running in the background. Until the sh program completes
go runOffMainProgram()
}
答案 2 :(得分:0)
一旦 go 程序完成,子进程(如果没有在 go 程序中等待)将继续运行(除非子进程自然在父 go 程序之前完成)。
原始发布者可能遇到的问题是他们可能提前终止了他们的 go 程序(例如使用 <Ctrl-c>
),并且因为 go 程序没有干净地退出,它产生的子进程也被终止了。
下面是一个简化的测试用例,有助于验证这种行为......
首先,我创建了一个我想运行的 bash shell 脚本(例如 test.sh
,不要忘记 chmod +x ./test.sh
所以脚本被认为是“可执行的”)。脚本非常简单。它休眠 10 秒,然后创建一个名为 testfile
的新文件(如果它不存在),或者如果该文件已经存在,它将更新“上次修改”时间戳。这很重要,因为这是我在 go 程序完成后确认 bash 脚本仍在运行的方式(由于 10 秒的睡眠,我希望在 bash 脚本完成之前很久)。
#!/usr/local/bin/bash
sleep 10
touch testfile
接下来,我有一个简单的 go 程序,它生成一个运行上面的 bash 脚本的子进程,但重要的是不等待它完成。你会看到我还在我的 go 程序中添加了 2 秒的睡眠,这让我有时间按下 <Ctrl-c>
。现在,即使我有 2 秒的睡眠时间,这个程序(如果在没有我按下 <Ctrl-c>
的情况下运行)将在子进程 bash 脚本执行之前完成(睡眠 10 秒):
package main
import (
"fmt"
"log"
"os/exec"
"time"
)
func main() {
cmd := exec.Command("./test.sh")
err := cmd.Start()
if err != nil {
log.Fatal(err)
}
time.Sleep(2 * time.Second)
fmt.Println("program finished, but what about the subprocess?")
}
如果我运行 go 程序并让它自然完成,我可以ls -l testfile
并检查它的时间戳。然后我将等待 10 秒并再次运行 ls -l testfile
,我将看到时间戳更新(显示子进程成功完成)。
现在如果我重新运行 go 程序,这次在程序结束前按下 <Ctrl-c>
(这就是我添加 2 秒睡眠的原因),那么不仅 go 程序会提前退出,而且子进程也将终止。所以我可以等待 10 秒或 10 小时或更长时间,没关系。 testfile
上的时间戳不会更新,证明子进程已终止。