ls -lah
func main() {
cmd := exec.Command("ls", "-lah")
if runtime.GOOS == "windows" {
cmd = exec.Command("tasklist")
}
err := cmd.Run()
if err != nil {
log.Fatalf("cmd.Run() failed with %s\n", err)
}
}
Linuxls -lahWindowstasklistshellshellstdoutstderr
func main() {
cmd := exec.Command("ls", "-lah")
if runtime.GOOS = "windows" {
cmd := exec.Command("tasklist")
}
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
err := cmd.Run()
if err != nil {
fmt.Printf("cmd.Run() failed with %s\n", err)
}
}
// total 8.0k
// drwxr-xr-x. 6 root root 120 Aug 20 14:38
// ...
cmd.Stdoutcmd.Stderrosos.Stdoutos.Stderros\file.goos\exec\exec.goCombinedOutputcmd
func (c *Cmd) CombinedOutput() ([]byte, error) {
if c.Stdout != nil {
return nil, errors.New("exec: Stdout already set")
}
if c.Stderr != nil {
return nil, errors.New("exec: Stderr already set")
}
var b bytes.Buffer
c.Stdout = &b
c.Stderr = &b
err := c.Run()
return b.Bytes(), err
}
CombinedOutputcmd
func main() {
out, err := exec.Command("ls", "-lah").CombinedOutput()
if err != nil {
fmt.Printf("CombinedOutput failed with %s\n", err)
}
fmt.Printf("combined out: %s\n", string(out))
}
// combined out: total 8.0k
// drwxr-xr-x. 6 root root 120 Aug 20 14:38
// ...
上面所有的示例都是将命令执行的结果保存到一个变量中,如果想把标准输出和标准错误分开来显示,需要像下面分开绑定。
func main() {
cmd := exec.Command("ls", "-lah")
var stdout, stderr bytes.Buffer
cmd.Stdout = &stdout
cmd.Stderr = &stderr
err := cmd.Run()
if err != nil {
fmt.Printf("cmd.Run failed with %s\n", err)
}
outStr, errStr := string(stdout.Bytes()), string(stderr.Bytes())
fmt.Printf("out: %s\n err: %s\n", outStr, errStr)
}
// out: total 8.0k
// drwxr-xr-x. 6 root root 120 Aug 20 14:38
// ...
// err:
Run
func (c *Cmd) Run() error {
if err := c.Start(); err != nil {
return err
}
return c.Wait()
}
上面的命令都是很快执行完,如果命令执行的时间较长,我们不仅需要最后的执行结果,还想看命令执行的过程,那该怎么办?
func main() {
cmd := exec.Command("ls", "-lah")
var stdout, stderr []byte
var errStdout, errStderr error
stdoutIn, _ := cmd.StdoutPipe()
stderrIn, _ := cmd.StderrPipe()
err := cmd.Start()
if err != nil {
log.Fatalf("cmd.Start failed with %s\n", err)
}
var wg sync.WaitGroup
wg.Add(1)
go func() {
stdout, errStdout = copyAndCapture(os.Stdout, stdoutIn)
wg.Done()
}
stderr, errStderr = copyAndCapture(os.Stderr, stderrIn)
wg.Wait()
if err = cmd.Wait(); err != nil {
log.Fatalf("cmd.Wait failed with %s\n", err)
}
if errStdout != nil || errStderr != nil {
log.Fatalf("failed to capture stdout or stderr\n")
}
outStr, errStr := string(stdout), string(stderr)
log.Fatalf("out: %s\n err: %s\n", outStr, errStr)
}
func copyAndCapture(w io.Writer, r io.Reader) ([]byte, error) {
var out []byte
buf := make([]byte, 1024, 1024)
for {
n, err := r.Read(buf[:])
if n > 0 {
d := buf[:n]
out = append(out, d...)
_, err := w.Write(d)
if err != nil {
return out, err
}
}
if err != nil {
if err == io.EOF {
err = nil
}
return out, err
}
}
}
StdoutPipeWaitWaitStdoutPipeRunRunWait
func (c *Cmd) StdoutPipe() (io.ReadCloser, error) {
if c.Stdout != nil {
return nil, errors.New("exec: Stdout already set")
}
if c.Process != nil {
return nil, errors.New("exec: StdoutPipe after process started")
}
pr, pw, err := os.Pipe()
if err != nil {
return nil, err
}
c.Stdout = pw
c.closeAfterStart = append(c.closeAfterStart, pw)
c.closeAfterWait = append(c.closeAfterWait, pr)
return pr, nil
}
type ReadCloser interface {
Reader
Closer
}
type Reader interface{
Read(p []byte) (n int, err error)
}
// Reader接口包裹基本的Read方法,它会读取长度为len(p)的字节到p中,并返回读取的字节个数n,n的取值范围为0<=n<=len(p)。也就是当n等于0时,说明读取出错。err!=nil,出现这种情况有两种主要原因:一是文件已经读取完;另一个是读取出错。