下方代码会执行 sngrep 抓包 1分钟,最后将其 kill -9.
基本用法
注意:
- 一定要有 Wait,不获取结果,会变成僵尸进程
cmd := exec.CommandContext(sw.ctx, FFMPEG_BIN, "-i", input, "-acodec", "pcm_s16le", "-f", "rtp", output)
sw.Logger.Infof("start cmd: %s", cmd.String())
if err := cmd.Start(); err != nil {
sw.Logger.Errorf("sw.readRtpToAsr done by cmd.Start err: %s", err.Error())
return
}
if err := cmd.Wait(); err != nil {
sw.Logger.Errorf("cmd exited with %s", err.Error())
}
获得输出
// 用 bytes.Buffer 类型做接收器,赋值给 cmd.Stdout
stdout := &bytes.Buffer{}
stderr := &bytes.Buffer{}
cmd.Stdout = stdout
cmd.Stderr = stderr
// 输出方法
stdoutStr := sw.CmdStdout.String()
Kill 掉
cmd.Process.Kill()
会让进程立即退出,但这一般不是你想要的退出。官网上解释说明了“Kill 不会等到进程实际退出”,来推测的话,应当时在创建进程的时候,会创建不仅仅一个进程(也可能仅在创建进程组后才是这样)。
官网解释:
Kill causes the Process to exit immediately. Kill does not wait until the Process has actually exited. This only kills the Process itself, not any other processes it may have started.
- 要用
cmd.SysProcAttr = &syscall.SysProcAttr{Setpgid: true}
,这是将子进程重新建立一个进程组,我们后面要 kill 整个进程组。 - kill 时用负值
syscall.Kill(-cmd.Process.Pid, syscall.SIGKILL)
,在man 2 kill
中有对传值更详细的介绍,传负数就是 kill 整个组(去详细看下)。 - kill 之后如果没有
cmd.Wait()
还是会变为僵尸进程,所以要有。另外看 exec 包文档,Release()
应该也可以。 - 注意执行的时候的权限,
man kill
去看下权限。 - 注意 syscall.Kill 只能在 linux 中执行
package main
import (
"fmt"
"os/exec"
"syscall"
"time"
)
func main() {
cmd := exec.Command("sngrep", "-c", "-N", "-q", "-O", "file.pcap")
cmd.SysProcAttr = &syscall.SysProcAttr{Setpgid: true}
err := cmd.Start()
if err != nil {
fmt.Println("err:", err)
return
}
fmt.Println("run pid ", cmd.Process.Pid)
defer func() {
if err = syscall.Kill(-cmd.Process.Pid, syscall.SIGKILL); err != nil {
fmt.Println(fmt.Printf("Kill sngrep (%d) failed with err %s", cmd.Process.Pid, err.Error()))
}
cmd.Wait()
}()
time.Sleep(1 * time.Minute)
}