Golang实现交互式Bash命令的自动化输入

Golang实现交互式Bash命令的自动化输入 大家好,

我正在尝试为一个交互式bash命令编写一个小的Go语言包装器。其目的是能够根据我从bash命令接收到的输出自动处理部分输入。

我的Go程序需要运行一个命令,读取其输出,并且每当该命令请求某些输入时,基于它产生的上一个输出:程序将决定是发送自动化的输入,还是像在没有Go包装器直接运行命令时那样手动输入。

我是Go语言的初学者,我认为这应该是一个简单的脚本,但我找不到任何合适的方法来实现它。我相信我需要使用goroutine,但到目前为止还没有成功。

有人能向我解释一下他/她会如何创建这个包装器吗?或者甚至可以给我发送一个能正常工作的小而简单的代码。

感谢您能提供的任何帮助!


更多关于Golang实现交互式Bash命令的自动化输入的实战教程也可以访问 https://www.itying.com/category-94-b0.html

2 回复

你可以直接尝试这个库:

GitHub

GitHub - spf13/cobra: 用于现代 Go CLI 交互的指挥官

缩略图

一个用于现代 Go CLI 交互的指挥官。通过在 GitHub 上创建账户来为 spf13/cobra 的开发做出贡献。

更多关于Golang实现交互式Bash命令的自动化输入的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


要实现交互式Bash命令的自动化输入,可以使用os/exec包配合io.Pipe和goroutine来处理输入输出流。下面是一个示例代码,演示如何根据命令输出自动响应输入:

package main

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

func main() {
    // 创建命令(示例:交互式Python解释器)
    cmd := exec.Command("python3", "-u", "-i")
    
    // 获取标准输入输出管道
    stdin, err := cmd.StdinPipe()
    if err != nil {
        log.Fatal(err)
    }
    stdout, err := cmd.StdoutPipe()
    if err != nil {
        log.Fatal(err)
    }
    stderr, err := cmd.StderrPipe()
    if err != nil {
        log.Fatal(err)
    }
    
    // 启动命令
    if err := cmd.Start(); err != nil {
        log.Fatal(err)
    }
    
    // 使用goroutine处理标准输出
    go func() {
        scanner := bufio.NewScanner(stdout)
        for scanner.Scan() {
            line := scanner.Text()
            fmt.Printf("输出: %s\n", line)
            
            // 根据输出内容自动响应
            if strings.Contains(line, ">>>") {
                // 检测到Python提示符,自动输入命令
                stdin.Write([]byte("print('自动响应')\n"))
            }
        }
    }()
    
    // 使用goroutine处理标准错误
    go func() {
        scanner := bufio.NewScanner(stderr)
        for scanner.Scan() {
            fmt.Printf("错误: %s\n", scanner.Text())
        }
    }()
    
    // 使用goroutine处理手动输入(如果需要)
    go func() {
        scanner := bufio.NewScanner(os.Stdin)
        for scanner.Scan() {
            input := scanner.Text()
            stdin.Write([]byte(input + "\n"))
        }
    }()
    
    // 等待命令结束
    if err := cmd.Wait(); err != nil {
        log.Fatal(err)
    }
}

更复杂的示例,实现完整的交互逻辑:

package main

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

type InteractiveCommand struct {
    cmd    *exec.Cmd
    stdin  io.WriteCloser
    stdout io.ReadCloser
    stderr io.ReadCloser
}

func NewInteractiveCommand(name string, args ...string) (*InteractiveCommand, error) {
    cmd := exec.Command(name, args...)
    
    stdin, err := cmd.StdinPipe()
    if err != nil {
        return nil, err
    }
    
    stdout, err := cmd.StdoutPipe()
    if err != nil {
        return nil, err
    }
    
    stderr, err := cmd.StderrPipe()
    if err != nil {
        return nil, err
    }
    
    return &InteractiveCommand{
        cmd:    cmd,
        stdin:  stdin,
        stdout: stdout,
        stderr: stderr,
    }, nil
}

func (ic *InteractiveCommand) Start() error {
    return ic.cmd.Start()
}

func (ic *InteractiveCommand) Run() error {
    // 启动命令
    if err := ic.Start(); err != nil {
        return err
    }
    
    // 创建输出扫描器
    stdoutScanner := bufio.NewScanner(ic.stdout)
    stderrScanner := bufio.NewScanner(ic.stderr)
    
    // 处理标准输出
    go func() {
        for stdoutScanner.Scan() {
            output := stdoutScanner.Text()
            fmt.Printf("命令输出: %s\n", output)
            
            // 根据输出内容决定输入
            ic.handleOutput(output)
        }
    }()
    
    // 处理标准错误
    go func() {
        for stderrScanner.Scan() {
            fmt.Printf("命令错误: %s\n", stderrScanner.Text())
        }
    }()
    
    return ic.cmd.Wait()
}

func (ic *InteractiveCommand) handleOutput(output string) {
    // 这里实现你的自动化逻辑
    // 示例:如果输出包含特定字符串,则自动响应
    
    switch {
    case strings.Contains(output, "请输入用户名:"):
        ic.SendInput("myusername\n")
    case strings.Contains(output, "请输入密码:"):
        ic.SendInput("mypassword\n")
    case strings.Contains(output, "[Y/n]"):
        ic.SendInput("Y\n")
    case strings.Contains(output, "选择操作"):
        ic.SendInput("1\n")
    }
}

func (ic *InteractiveCommand) SendInput(input string) error {
    _, err := ic.stdin.Write([]byte(input))
    return err
}

func main() {
    // 示例:自动化SSH连接
    ic, err := NewInteractiveCommand("ssh", "user@hostname")
    if err != nil {
        log.Fatal(err)
    }
    
    // 可以添加初始命令
    ic.SendInput("ls -la\n")
    
    if err := ic.Run(); err != nil {
        log.Fatal(err)
    }
}

简单包装器示例,用于处理需要确认的命令:

package main

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

func runInteractiveCommand(cmdStr string, responses map[string]string) error {
    cmd := exec.Command("bash", "-c", cmdStr)
    
    stdin, _ := cmd.StdinPipe()
    stdout, _ := cmd.StdoutPipe()
    
    cmd.Start()
    
    // 读取输出并自动响应
    reader := bufio.NewReader(stdout)
    go func() {
        for {
            line, err := reader.ReadString('\n')
            if err != nil {
                break
            }
            
            fmt.Print(line)
            
            // 检查是否需要自动响应
            for prompt, response := range responses {
                if strings.Contains(line, prompt) {
                    stdin.Write([]byte(response + "\n"))
                    break
                }
            }
        }
    }()
    
    return cmd.Wait()
}

func main() {
    // 定义命令和自动响应
    responses := map[string]string{
        "Are you sure": "yes",
        "Continue":     "y",
        "Password":     "secret123",
    }
    
    // 运行需要交互的命令
    err := runInteractiveCommand("sudo apt-get update && sudo apt-get upgrade", responses)
    if err != nil {
        fmt.Printf("命令执行错误: %v\n", err)
    }
}

这些示例展示了如何捕获命令输出、分析输出内容并自动发送响应。关键点包括:

  1. 使用exec.Command创建命令
  2. 通过StdinPipeStdoutPipeStderrPipe获取输入输出流
  3. 使用goroutine并发处理输入输出
  4. 根据输出内容通过Write方法发送输入响应
回到顶部