背景 golang可以獲取命令執行的輸出結果,但要執行完才能夠獲取。 如果執行的命令是ssh,我們要實時獲取,並執行相應的操作呢? 示例 func main() { user := "root" host := "172.16.116.133" //獲取執行命令 cmd := exec.Comman ...
背景
- 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
}
那年,郭少在京城。