背景

  • 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
}

那年,郭少在京城。

golang执行命令 && 实时获取输出结果的更多相关文章

  1. java执行cmd命令并获取输出结果

    1.java执行cmd命令并获取输出结果 import java.io.BufferedReader; import java.io.InputStreamReader; import org.apa ...

  2. C语言使用cmd命令并获取输出方法

    转自http://blog.csdn.net/hxh129/article/details/8000205 C语言使用cmd命令并获取输出方法 在实践中,我们有时候需要用C语言来调用cmd的命令,并得 ...

  3. 使用Python执行dos命令并获取输出的结果

    import os import subprocess # 第一种 result1 = subprocess.check_output('dir').decode('GBK') print(resul ...

  4. python执行外部命令并获取输出

    使用subprocess库 import subprocess out_bytes = subprocess.check_output(['netstat','-a']) out_bytes = su ...

  5. Python执行Linux cmd命令,获取输出的一种方法,输出是bytes

    import subprocess p = subprocess.Popen('df -lh', stdout=subprocess.PIPE, shell=True) print(p.stdout. ...

  6. golang执行命令行(一)

    golang中会经常遇到要 fork 子进程的需求.go 标准库为我们封装了 os/exec标准包,当我们要运行外部命令时应该优先使用这个库. 执行 command 这里我简单结合context 和 ...

  7. golang 执行命令行(二)--修改进程启动用户

    继续上文所述,有时候我们需要设置进程的启动用户,操作与设置进程组的方式类似,不多说直接上代码: // 修改进程的执行用户 func withUserAttr(cmd *exec.Cmd, name s ...

  8. c# 调用CMD命令并获取输出结果

    private static string CMDPath = Environment.GetFolderPath(Environment.SpecialFolder.System) + " ...

  9. [golang][译]使用os/exec执行命令

    [golang][译]使用os/exec执行命令 https://colobu.com/2017/06/19/advanced-command-execution-in-Go-with-os-exec ...

  10. 模拟远程SSH执行命令的编解码说明

    模拟一个SSH“远程”执行命令并获取命令结果的一个程序: 1.在C/S架构下,当客户端与服务器建立连接(这里以TCP为例)后,二者可以不断的进行数据交互.SSH远程可以实现的效果是客户端输入命令可以在 ...

随机推荐

  1. 使用ssh连接远程仓库的方法(github)

    使用ssh连接远程仓库的方法 但是当我登录虚拟机想提交csapp的代码时,我发现需要验证我的账号密码,感觉每次提交都要输入这个很麻烦.然后就在网上查询了下为何提交代码需要输入账号密码. 使用 HTTP ...

  2. WPF 已知问题 某些设备上的应用在 WindowChromeWorker 抛出 System.OverflowException 异常

    准确来说,这个不算是 WPF 的问题,而是系统等的问题.在某些设备上的使用了 WindowChrome 功能的 WPF 应用,将在运行过程,在 WindowChromeWorker 类里面抛出 Sys ...

  3. Prometheus+Grafana+alertmanager构建企业级监控系统(三)

    七.Prometheus监控扩展 7.1 Promethues 采集tomcat监控数据 tomcat_exporter地址:https://github.com/nlighten/tomcat_ex ...

  4. VGA显示文字

    VGA显示文字 VGA字符显示的原理 把要显示的字符转换成字符点阵,然后编码存储,着色的部分为1,其它为0.然后在VGA上输出显示. 字符点阵生成软件: https://www.zhetao.com/ ...

  5. 用Vue仿了一个类似抖音的App

    大家好,我是 Java陈序员. 今天,给大家介绍一个基于 Vue3 实现的高仿抖音开源项目. 关注微信公众号:[Java陈序员],获取开源项目分享.AI副业分享.超200本经典计算机电子书籍等. 项目 ...

  6. 普冉PY32系列(十五) PY32F0系列的低功耗模式

    目录 普冉PY32系列(一) PY32F0系列32位Cortex M0+ MCU简介 普冉PY32系列(二) Ubuntu GCC Toolchain和VSCode开发环境 普冉PY32系列(三) P ...

  7. MAPREDUCE实践篇

    1.编程规范 (1)用户编写的程序分成三个部分:Mapper,Reducer,Driver(提交运行mr程序的客户端) (2)Mapper的输入数据是KV对的形式(KV的类型可自定义) (3)Mapp ...

  8. Spring 对 Junit4,Junit5 的支持上的运用

    1. Spring 对 Junit4,Junit5 的支持上的运用 @ 目录 1. Spring 对 Junit4,Junit5 的支持上的运用 每博一文案 2. Spring对Junit4 的支持 ...

  9. wxPython==4.2.1 aui.AuiToolBar 如何去掉烦人的抓手?

    aui.AuiToolBar 如何去掉烦人的抓手? 最近在用wxPython做一些GUI小应用,发现工具栏总有几个点(抓手),很影响美观,如下: 目前官方没有提供隐藏抓手的功能,需要更改源码的auib ...

  10. Java21新特性-虚拟线程

    虚拟线程是轻量级线程(类似于 Go 中的 "协程(Goroutine)"),可以减少编写.维护和调度高吞吐量并发应用程序的工作量. 线程是可供调度的最小处理单元,它与其他类似的处理 ...