首页  >  文章  >  后端开发  >  如何在Go中执行命令并将其与父进程分离?

如何在Go中执行命令并将其与父进程分离?

Patricia Arquette
Patricia Arquette原创
2024-10-29 04:35:02960浏览

How to Execute a Command in Go and Detach It from the Parent Process?

在 Go 中运行命令并将其与进程分离

在 Go 中,您可以以分离的方式执行命令,使其能够运行独立于您的程序。以下是实现此目的的方法:

代码:

<code class="go">package main

import (
    "fmt"
    "log"
    "os"
    "os/exec"
    "strconv"
    "syscall"
)

func main() {
    // Define the command and its arguments
    cmd := exec.Command("sleep", "120")

    // Set up the pipes for stdout and stderr
    stdoutPipe, err := cmd.StdoutPipe()
    if err != nil {
        log.Fatal(err)
    }
    stderrPipe, err := cmd.StderrPipe()
    if err != nil {
        log.Fatal(err)
    }

    // Start the command
    if err := cmd.Start(); err != nil {
        log.Fatal(err)
    }

    // Get the process ID (PID) of the child process
    pid := cmd.Process.Pid

    // Print the PID
    fmt.Printf("PID: %d\n", pid)

    // Read from the stdout and stderr pipes and log the output
    go func() {
        for {
            buf := make([]byte, 1024)
            n, err := stdoutPipe.Read(buf)
            if err != nil {
                log.Fatal(err)
            }
            fmt.Printf("stdout: %s", string(buf[:n]))
        }
    }()
    go func() {
        for {
            buf := make([]byte, 1024)
            n, err := stderrPipe.Read(buf)
            if err != nil {
                log.Fatal(err)
            }
            fmt.Printf("stderr: %s", string(buf[:n]))
        }
    }()

    // Wait for the command to finish
    if err := cmd.Wait(); err != nil {
        if exitErr := cmd.ProcessState.Sys().(syscall.WaitStatus).ExitStatus(); exitErr != 0 {
            log.Fatal(fmt.Sprintf("Error #48692663: Command exited with code %d", exitErr))
        } else {
            log.Printf("Command exited with exit code 0")
        }
    }

    // Optionally, keep the child process alive even after the parent process exits
    // This can be achieved by setting `cmd.SysProcAttr = &syscall.SysProcAttr{Setpgid: true}` before starting the command.

    // Example of sending a signal to the detached process
    if err := syscall.Kill(pid, os.Interrupt); err != nil {
        log.Fatalf("Error sending signal to process: %d: %s", pid, err)
    } else {
        fmt.Printf("Received ^C and forwarded to process %d\n", pid)
    }

    // Optionally, use `syscall.Reap()` to clean up any child processes that are terminated but not yet waited for.
}</code>

此代码演示了如何以分离的方式执行命令,使其能够独立于其他命令继续运行父进程。它提供了诸如捕获 stdout 和 stderr、获取进程 ID 以及选择性地向子进程发送信号等功能。

关键注意事项:

  • 请注意分离进程并不能阻止它在父进程退出时成为孤立进程,因为内核仍然保留对它的引用。
  • 使用 SysProcAttr.Setpgid 可以使子进程独立地保持活动状态,但可能需要额外的操作在某些情况下进行处理。
  • 请务必使用 Wait() 以确保进程返回退出代码,并且您可以处理任何潜在的错误。
  • 使用 syscall.Reap() 进行清理僵尸进程以避免资源泄漏。

以上是如何在Go中执行命令并将其与父进程分离?的详细内容。更多信息请关注PHP中文网其他相关文章!

声明:
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn