程序VS命令

  • 执行程序: /usr/bin/python xxx.py
  • 调用命令: cat nginx.log | grep “something”

命令解释器bash

  • 交互模式: ls -al
  • 非交互模式: /bin/bash -c “ls -al”

/bin/bash -c “命令”

任务执行原理

  • 提交任务->创建管道->fork子进程->重定向输出->exec执行/bin/bash程序->输出到管道
  • pipe(): 创建2个文件描述符, fd[0]可读, fd[1]可写
  • fork(): 创建子进程, fd[1]被继承到子进程
  • dup2(): 重定向子进程stdout/stderr到fd[1]
  • exec(): 在当前进程内, 加载并执行二进制程序

执行命令, 捕获了子进程的输出(pipe)

  1. func main() {
  2. // 生成cmd
  3. cmd := exec.Command("/bin/bash", "-c", "sleep 5; ls -al")
  4. // 执行命令, 捕获了子进程的输出(pipe)
  5. if output, err := cmd.CombinedOutput(); err != nil {
  6. fmt.Println(err)
  7. return
  8. } else {
  9. // 打印子进程的输出
  10. fmt.Println(string(output))
  11. }
  12. }

执行cmd, 杀死

  1. type result struct {
  2. err error
  3. output []byte
  4. }
  5. func main() {
  6. ctx, cancelFunc := context.WithCancel(context.TODO())
  7. // 创建了一个结果队列
  8. resultChan := make(chan *result, 1000)
  9. go func() {
  10. cmd := exec.CommandContext(ctx, "/bin/bash", "-c", "sleep 2; echo hello;")
  11. // 执行任务, 捕获输出
  12. output, err := cmd.CombinedOutput()
  13. // 把任务输出结果, 传给main协程
  14. resultChan <- &result{
  15. err: err,
  16. output: output,
  17. }
  18. }()
  19. time.Sleep(1 * time.Second)
  20. // 取消上下文
  21. cancelFunc()
  22. // main协程里, 等待子协程的退出,并打印任务执行结果
  23. res := <-resultChan
  24. // 打印任务执行结果
  25. fmt.Println(res.err, string(res.output))
  26. }