在 Golang 中,如何使用 SIGTERM 而不是 SIGKILL 终止 os.exec.Cmd 进程?

In Golang, how to terminate an os.exec.Cmd process with a SIGTERM instead of a SIGKILL?

目前,我正在使用 Golang os.exec.Cmd.Process.Kill() 方法(在 Ubuntu 框上)终止进程。

这似乎是立即终止进程,而不是正常终止。我启动的一些进程也会写入文件,这会导致文件被截断。

我想使用 SIGTERM 而不是使用 Golang 的 SIGKILL 优雅地终止进程。

这是一个使用 cmd.Process.Kill() 启动然后终止的进程的简单示例,我想要 Golang 中使用 SIGTERM 而不是 SIGKILL 的 Kill() 方法的替代方法,谢谢!

import "os/exec"

cmd := exec.Command("nc", "example.com", "80")
if err := cmd.Start(); err != nil {
   log.Print(err)
}
go func() {
  cmd.Wait()
}()
// Kill the process - this seems to kill the process ungracefully
cmd.Process.Kill()
cmd.Process.Signal(syscall.SIGTERM)

你可以用Signal() API. The supported Syscalls都在这里

所以基本上你可能想使用

cmd.Process.Signal(syscall.SIGTERM)

另请根据文档注意。

The only signal values guaranteed to be present in the os package on all systems are os.Interrupt (send the process an interrupt) and os.Kill (force the process to exit). On Windows, sending os.Interrupt to a process with os.Process.Signal is not implemented; it will return an error instead of sending a signal.

您可以使用:

cmd.Process.Signal(os.Interrupt)

测试示例:

package main

import (
    "fmt"
    "log"
    "net"
    "os"
    "os/exec"
    "sync"
    "time"
)

func main() {
    cmd := exec.Command("nc", "-l", "8080")
    cmd.Stderr = os.Stderr
    cmd.Stdout = os.Stdout
    cmd.Stdin = os.Stdin
    err := cmd.Start()
    if err != nil {
        log.Fatal(err)
    }

    var wg sync.WaitGroup
    wg.Add(1)
    go func() {
        err := cmd.Wait()
        if err != nil {
            fmt.Println("cmd.Wait:", err)
        }
        fmt.Println("done")
        wg.Done()
    }()

    fmt.Println("TCP Dial")
    fmt.Println("Pid =", cmd.Process.Pid)
    time.Sleep(200 * time.Millisecond)
    // or comment this and use: nc 127.0.0.1 8080
    w1, err := net.DialTimeout("tcp", "127.0.0.1:8080", 1*time.Second)
    if err != nil {
        log.Fatal("tcp DialTimeout:", err)
    }
    defer w1.Close()

    fmt.Fprintln(w1, "Hi")
    time.Sleep(1 * time.Second)
    // cmd.Process.Kill()
    cmd.Process.Signal(os.Interrupt)
    wg.Wait()
}

输出:

TCP Dial
Pid = 21257
Hi
cmd.Wait: signal: interrupt
done