程序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() {
// 生成cmd
cmd := 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 error
output []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))
}