程序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)
func main() {// 生成cmdcmd := exec.Command("/bin/bash", "-c", "sleep 5; ls -al")// 执行命令, 捕获了子进程的输出(pipe)if output, err := cmd.CombinedOutput(); err != nil {fmt.Println(err)return} else {// 打印子进程的输出fmt.Println(string(output))}}
执行cmd, 杀死
type result struct {err erroroutput []byte}func main() {ctx, cancelFunc := context.WithCancel(context.TODO())// 创建了一个结果队列resultChan := make(chan *result, 1000)go func() {cmd := exec.CommandContext(ctx, "/bin/bash", "-c", "sleep 2; echo hello;")// 执行任务, 捕获输出output, err := cmd.CombinedOutput()// 把任务输出结果, 传给main协程resultChan <- &result{err: err,output: output,}}()time.Sleep(1 * time.Second)// 取消上下文cancelFunc()// 在main协程里, 等待子协程的退出,并打印任务执行结果res := <-resultChan// 打印任务执行结果fmt.Println(res.err, string(res.output))}
