首页 > 其他分享 >golang执行命令 && 实时获取输出结果

golang执行命令 && 实时获取输出结果

时间:2023-02-19 17:01:15浏览次数:25  
标签:wg 输出 执行命令 err fmt cmd golang && os

背景

  • golang可以获取命令执行的输出结果,但要执行完才能够获取。
  • 如果执行的命令是ssh,我们要实时获取,并执行相应的操作呢?

示例

func main() {
	user := "root"
	host := "172.16.116.133"

	//获取执行命令
	cmd := exec.Command("ssh", fmt.Sprintf("%s@%s", user, host))
	cmd.Stdin = os.Stdin

	var wg sync.WaitGroup
	wg.Add(2)
	//捕获标准输出
	stdout, err := cmd.StdoutPipe()
	if err != nil {
		fmt.Println("ERROR:", err)
		os.Exit(1)
	}
	readout := bufio.NewReader(stdout)
	go func() {
		defer wg.Done()
		GetOutput(readout)
	}()

	//捕获标准错误
	stderr, err := cmd.StderrPipe()
	if err != nil {
		fmt.Println("ERROR:", err)
		os.Exit(1)
	}
	readerr := bufio.NewReader(stderr)
	go func() {
		defer wg.Done()
		GetOutput(readerr)
	}()

	//执行命令
	cmd.Run()
	wg.Wait()
	return
}
func GetOutput(reader *bufio.Reader) {
	var sumOutput string				//统计屏幕的全部输出内容
	outputBytes := make([]byte, 200)
	for {
		n, err := reader.Read(outputBytes)		//获取屏幕的实时输出(并不是按照回车分割,所以要结合sumOutput)
		if err != nil {
			if err == io.EOF {
				break
			}
			fmt.Println(err)
			sumOutput += err.Error()
		}
		output := string(outputBytes[:n])
		fmt.Print(output) //输出屏幕内容
		sumOutput += output
	}
	return
}

应用场景

ssh是交互式命令,本示例实现了实时获取输出结果,并判断输出结果中有没有报错,报错则重试(再次登陆)。
场景:本Demo只是把"错误"二字视为异常,然后重试,实际上比这复杂的多,比如ssh连接超时重试等,这个逻辑请自行补充。

package main

import (
	"bufio"
	"fmt"
	"io"
	"os"
	"os/exec"
	"strings"
	"sync"
	"time"
)

func main(){
	retryTimes := 3
	var retryInterval time.Duration = 3
	user := "root"
	host := "172.16.116.133"

	//部分场景下重试登录
	shouldRetry := true
	for i:=1;i<=retryTimes && shouldRetry;i++{
		//执行命令
		shouldRetry = RunSSHCommand(user,host)
		if !shouldRetry{
			return
		}
		time.Sleep(retryInterval * time.Second)
	}
	if shouldRetry{
		fmt.Println("\n失败,请重试或检查")
	}
}
func shouldRetryByOutput(output string)bool{
	if strings.Contains(output,"错误"){		//匹配到"错误"就重试.这里只是Demo,请根据实际情况设置。
		return true
	}
	return false
}
func GetAndFilterOutput(reader *bufio.Reader)(shouldRetry bool){
	var sumOutput string
	outputBytes:= make([]byte,200)
	for {
		n,err := reader.Read(outputBytes)
		if err!=nil{
			if err == io.EOF{
				break
			}
			fmt.Println(err)
			sumOutput += err.Error()
		}
		output := string(outputBytes[:n])
		fmt.Print(output)		//输出屏幕内容
		sumOutput += output
		if shouldRetryByOutput(output){
			shouldRetry = true
		}
	}
	if shouldRetryByOutput(sumOutput){
		shouldRetry = true
	}
	return
}
func RunSSHCommand(user,host string)(shouldRetry bool){
	//获取执行命令
	cmd := exec.Command("ssh",fmt.Sprintf("%s@%s",user,host))
	cmd.Stdin = os.Stdin

	var wg sync.WaitGroup
	wg.Add(2)
	//捕获标准输出
	stdout, err := cmd.StdoutPipe()
	if err != nil {
		fmt.Println("ERROR:",err)
		os.Exit(1)
	}
	readout := bufio.NewReader(stdout)
	go func() {
		defer wg.Done()
		shouldRetryTemp := GetAndFilterOutput(readout)
		if shouldRetryTemp{
			shouldRetry = true
		}
	}()

	//捕获标准错误
	stderr, err := cmd.StderrPipe()
	if err != nil {
		fmt.Println(err)
		os.Exit(1)
	}
	readerr := bufio.NewReader(stderr)
	go func() {
		defer wg.Done()
		shouldRetryTemp := GetAndFilterOutput(readerr)
		if shouldRetryTemp{
			shouldRetry = true
		}
	}()

	//执行命令
	cmd.Run()
	wg.Wait()
	return
}




那年,郭少在京城。

标签:wg,输出,执行命令,err,fmt,cmd,golang,&&,os
From: https://www.cnblogs.com/NetRookieX/p/17135036.html

相关文章

  • Golang数据结构
    数据类型不同类型的内存样式图查看变量类型使用fmt.Printfpackagemainimport"fmt"funcmain(){str:="Helloworld"fmt.Printf("%T",str)}使用re......
  • Golang基础-随机数
    import"math/rand"n:=rand.Intn(100)//nisarandomint,0<=n<100f:=rand.Float64()//fisarandomfloat64,0.0<=f<1.0x:=[]string{"a","b",......
  • Golang基础-Structs与Methods
    将struct定义为一种类型CarNewCar函数return&Car{},返回指针//car.gopackageelon//Carimplementsaremotecontrolledcar.typeCarstruct{ speed......
  • golang 数组
    1.概念golang中的数组是具有固定长度及相同数据类型的序列集合2.初始化数组var数组名[数组大小]数据类型packagemainimport"fmt"funcmain(){ //第一种 v......
  • Golang字符串拼接
    使用+funcplusConcat(nint,strstring)string{ s:="" fori:=0;i<n;i++{ s+=str } returns}使用fmt.SprintffuncsprintfConcat(nint,str......
  • Golang基础-Switch
    不需要手动breakdefault是找不到case时执行可以对多个case执行同样的操作operatingSystem:="windows"switchoperatingSystem{case"windows","linux"://......
  • golang for 循环
    1.for循环for循环是Golang唯一的循环语句。for初始表达式;布尔表达式;迭代因子{循环体;}packagemainimport"fmt"funcmain(){ fori:=0;i<5;i++{......
  • golang 单测运行单个函数、文件、跳过文件命令
    1、单测运行1.2运行某个单测函数gotest-v-run=xxx,xxx是函数名,支持正则表达式;参数-v说明需要打印详情提示Golang单测是根据前缀匹配来执行的,gotest-v-run=......
  • Golang基础-Slices
    声明Slicevarempty[]int//anemptyslicewithData:=[]int{0,1,2,3,4,5}//aslicepre-filledwithsomedatamake([]T,len)make([]T,len,......
  • Golang基础-格式化输出
    General%v thevalueinadefaultformat whenprintingstructs,theplusflag(%+v)addsfieldnames%#v aGo-syntaxrepresentationofthevalue%T aGo-synta......