## 问题
exec.Command是Go标准库提供了一个可以很容易地运行外部命令的方法,但是如果使用不当会容易出现僵尸进程的问题。
> 僵尸进程:一个进程使用fork创建子进程,如果子进程退出,而父进程并没有调用wait或waitpid获取子进程的状态信息,那么子进程的进程描述符仍然保存在系统中。这种进程称之为僵死进程。
exec.Command执行的方法有两种,一种是直接调用Run()方法:
```go
cmd := exec.Command("ls")
cmd.Run()
```
另外一种是用start方法
```go
cmd := exec.Command("ls")cmd.Start()
cmd.Wait()
```
区别在于
- Run()方法是在“ls”执行完后才返回
- Start()方法则是异步的,方法调用完并不是代表结束,需要配合cmd.Wait()
Run和Start方式本质是一样的,查看Run()方法的代码,可以看到实际上也是调用Start后直接调用Wait(),等待Wait返回
```go
func (c *Cmd) Run() error {
if err := c.Start(); err != nil {
return err
}
return c.Wait()
}
```
Wait的功能就是获取子进程的状态,如果不调用就会导致僵尸进程的,可以用一下例子验证:
执行
```go
func main() {
cmd := exec.Command("ls")
cmd.Start()
time.Sleep(100* time.Second)
}
```
查询僵尸进程(mac)
```
✗ ps -A -ostat,ppid,pid,command | grep -e '^[Zz]'
Z+ 24625 24626 (ls) // 结果出现一个僵尸进程
```
## 结论
cmd.Start()后要记得调用Wait方法,否则会出现僵尸进程
我的博客:[exec.Command僵尸进程问题 | 艺术码农的小栈](https://itart.cn/blogs/2021/practice/exec-command-zombie.html)
有疑问加站长微信联系(非本文作者))