Golang 执行 shell 脚本,不接收返回值

// 返回一个 cmd 对象
cmd := exec.Command("sh", "-c", "./scripts/curl.sh")

// 如果只执行命令,不接收返回值
cmd.Run()

Run(),命令其实是调用了 cmd.Start()和 cmd.Wait()两个方法,只返回一个 error 对象

 

Golang 执行 shell脚本,接收返回值

// 返回一个 cmd 对象
cmd := exec.Command("sh", "-c", "./scripts/curl.sh")

// 收返回值[]byte, error
b,er:= cmd.Output()

log.Pringln(string(b))

        返回值就是 shell 脚本打印的日志信息,但这样有一个缺点,golang 接收 shell 脚本的打印结果,必须要等待 shell 脚本全部执行完成才能一次性返回

 

Golang 执行 shell脚本,并实时打印 shell 脚本输出日志信息

实际业务比如:异步任务调度系统、自动发布系统等都有可能需要 shell 脚本的配合来完成,就需要实时打印 shell 脚本的中每条命令的输出日志信息,便于查看任务进度等

package main

import (
	"fmt"
	"io"
	"log"
	"os/exec"
	"strings"
)

func asyncLog(reader io.ReadCloser) error {
	cache := "" //缓存不足一行的日志信息
	buf := make([]byte, 1024)
	for {
		num, err := reader.Read(buf)
		if err != nil && err!=io.EOF{
			return err
		}
		if num > 0 {
			b := buf[:num]
			s := strings.Split(string(b), "\n")
			line := strings.Join(s[:len(s)-1], "\n") //取出整行的日志
			fmt.Printf("%s%s\n", cache, line)
			cache = s[len(s)-1]
		}
	}
	return nil
}

func execute() error {
	cmd := exec.Command("sh", "-c", "./scripts/curl.sh")

	stdout, _ := cmd.StdoutPipe()
	stderr, _ := cmd.StderrPipe()

	if err := cmd.Start(); err != nil {
		log.Printf("Error starting command: %s......", err.Error())
		return err
	}

	go asyncLog(stdout)
	go asyncLog(stderr)

	if err := cmd.Wait(); err != nil {
		log.Printf("Error waiting for command execution: %s......", err.Error())
		return err
	}

	return nil
}

func main(){
	execute()
}

shell脚本,每秒打印时间,观察 Golang 对日志的实时输出

#!/bin/bash

#print time
for((i=0;i<10;i++))
do
    sleep 1
    echo $(date +"%Y-%m-%d %H:%M:%S")
done