Golang 运行和管理命令

本文介绍了在Golang中如何使用Run()和Start()方法执行并管理命令,CombinedOutput()的使用,以及如何杀死和完全终止进程及其子进程,包括信号处理和goroutine的协作。
摘要由CSDN通过智能技术生成

有时候我们要在程序里面运行一个程序, 并对其进行管理.

以下是部分经验分享.

1. Run()Start() 的区别

cmd := exec.Command("your-command", "your-args")
err := cmd.Start()
// err := cmd.Run()

查看源码:

// Run starts the specified command and waits for it to complete.
//
// The returned error is nil if the command runs, has no problems
// copying stdin, stdout, and stderr, and exits with a zero exit
// status.
//
// If the command starts but does not complete successfully, the error is of
// type *ExitError. Other error types may be returned for other situations.
//
// If the calling goroutine has locked the operating system thread
// with runtime.LockOSThread and modified any inheritable OS-level
// thread state (for example, Linux or Plan 9 name spaces), the new
// process will inherit the caller's thread state.
func (c *Cmd) Run() error {
	if err := c.Start(); err != nil {
		return err
	}
	return c.Wait()
}

Run() 调用的就是 Start() 但是还调用了一个 Wait() 方法.

  • Start() 会执行一个命令, 但是不会等待命令执行完成
  • Run() 会执行一个命令, 并等待命令执行完成

2. 运行结果

CombinedOutput() 方法会执行命令, 并且返回结果. 但是会等待命令执行完成后才返回结果. 它调用了 Run()

如果我们希望命令执行的过程中实时输出命令运行中的输出, 可以使用以下方式:

// 设置输出和错误的处理方式
cmd := exec.Command("your-command", "your-args")

cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr

err := cmd.Run()

3. 杀死一个命令

以下命令就可以杀死运行的命令

cmd.Process.Kill()

如果我们运行的命令又创建了子进程, 甚至更甚层次的进程, 这个命令只能杀死我们运行的那个进程, 子进程依然会继续运行.

如果想彻底杀死运行的命令以及其创建的子进程, 可以使用以下方式:

cmd := exec.Command("your-command", "your-args")

// 创建新的进程组
cmd.SysProcAttr = &syscall.SysProcAttr{Setpgid: true}

err := cmd.Run()
if err != nil {
    panic(err)
}
pgid, err := syscall.Getpgid(cmd.Process.Pid)
if err != nil {
    panic(err)
}

syscall.Kill(-pgid, syscall.SIGKILL)

需要注意的是要添加 cmd.SysProcAttr = &syscall.SysProcAttr{Setpgid: true} 否则会连我们执行命令的程序也杀死.

程序进程的信号可以参考Golang 程序进程信号汇总

但是这个又会有一个新的问题, 就是执行命令的程序终止运行后, 程序中创建的进程组还在运行. 这时要做多一步, 监听进程的信号, 如果是终止运行, 则首先杀死运行中的程序, 再退出.

    // 创建一个接收信号的 channel
    sigs := make(chan os.Signal, 1)

    // 使用 signal.Notify 注册你想要监听的信号
    signal.Notify(sigs, syscall.SIGINT, syscall.SIGTERM)

    go func() {
        // 在一个 goroutine 中等待信号
        sig := <-sigs
        fmt.Println()
        fmt.Println(sig)
        os.Exit(0)
    }()

    fmt.Println("awaiting signal")
    select {}
  • 16
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值