背景
- 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
}
那年,郭少在京城。
来源:https://www.cnblogs.com/NetRookieX/p/17135036.html
本站部分图文来源于网络,如有侵权请联系删除。