os.Wait() 在 golang 中不等待程序终止

问题描述

在我的代码执行过程中的某个时刻,我希望我的程序启动一个编辑器(不管是哪个),以便用户执行一些实时编辑。

此时我需要我的程序停止,直到用户决定关闭编辑器(或多或少是 git rebase 的工作原理)

这就是我的做法

func main() {
    fpath := os.TempDir() + "/afile.txt"
    f,err := os.Create(fpath)
    if err != nil {
        log.Fatal(err)
    }
    defer f.Close()
    cmd := exec.Command("/usr/local/bin/code",fpath)
    err = cmd.Start()
    if err != nil {
        log.Fatal(err)
    }
    err = cmd.Wait()
    if err != nil {
        fmt.Println(err)
    }
}

不会打印任何错误,但是上面的代码,虽然它当然打开 vscode,但它在用户关闭编辑器之前终止(返回)。

cmd.Wait() 不应该处理这个问题吗?

程序在 MacOS Catalina fwiw 上执行。

解决方法

cmd.Wait() 不应该处理这个吗?

是的,确实如此。 Go 按预期等待,这是您对 /usr/local/bin/code 的调用不正确,并且不等待。 code 的默认行为是在生成 VSCode 窗口后立即退出。它不会等待窗口关闭,所以 Go 不能等待窗口关闭。

尝试在终端中简单地输入 code。你会发现它立即退出,即使你的 VSCode 窗口仍然打开。

要使 code 阻塞直到编辑器窗口关闭(从而允许 Go 等待),您需要将 -w--wait 标志传递给它。再次在终端中尝试 code -w。在 VSCode 窗口关闭之前,您会找到终端命令块。

实际上,您只需要更改此...

    cmd := exec.Command("/usr/local/bin/code",fpath)

为此:

    cmd := exec.Command("/usr/local/bin/code","-w",fpath)
    // or
    // cmd := exec.Command("/usr/local/bin/code","--wait",fpath)
,

根据https://golang.org/pkg/os/exec/#Cmd.Start

Start 启动指定的命令但不等待它执行 完成。

如果 Start 成功返回,c.Process 字段将被设置。

Wait 方法将返回退出代码并释放关联 命令退出后的资源。

如果你能strace code,你会在 linux 的底部找到 +++ exited with 0 +++

基本上,启动 vscode 的命令会退出,clones(一种 fork)因此不会等待返回。

strace code -w 实际上是在等待 vscode 退出。