dsjzmrz78089 2014-12-05 18:49
浏览 26
已采纳

从代码内部与外部应用程序进行交互

I need to be able to run an external application and interact with it as though I was manually running it from the command-line. All the examples I find only deal with running the program and capturing the output.

Below is a very simple example that I hope illustrates what I am trying to accomplish.

package main

import (
    "fmt"
    "log"
    "os/exec"
)

func main() {

  cmd := exec.Command("rm", "-i", "somefile.txt")
  out, err := cmd.CombinedOutput()
  if err != nil {
    log.Fatal(err)
  }
  if string(out) == "Remove file 'somefile.txt'?" {
    // send the response 'y' back to the rm process
  }

  // program completes normally...

}

I've tried to tweak various examples that I've found to accomplish this with zero success. It seems that even though 'rm' is waiting for a response, Go closes the process.

Any examples, articles, or advice you can provide would be greatly appreciated. Many thanks in advance.

  • 写回答

1条回答 默认 最新

  • doufeixuan8882 2014-12-05 21:34
    关注

    You have two possibilities. First is to use ReadLine() but that works only if application output is full lines, and you can wait for . This is not the case with rm, so you have to develop a custom SplitFunction for Scanner. Both versions can be found below.

    Please note that you can not use CombinedOutput, as it can not be Scanned. You have to use the pipes.

    package main
    
    import (
        "bufio"
        //"fmt"
        "log"
        "os/exec"
    )
    
    func main() {
    
        cmd := exec.Command("rm", "-i", "somefile.txt")
    
        // Stdout + stderr
        out, err := cmd.StderrPipe() // rm writes the prompt to err
        if err != nil {
            log.Fatal(err)
        }
        r := bufio.NewReader(out)
    
        // Stdin
        in, err := cmd.StdinPipe()
        if err != nil {
            log.Fatal(err)
        }
        defer in.Close()
    
        // Start the command!
        err = cmd.Start()
        if err != nil {
            log.Fatal(err)
        }
    
        line, _, err := r.ReadLine()
    
        for err != nil {
            if string(line) == "Remove file 'somefile.txt'?" {
                in.Write([]byte("y
    "))
            }
            line, _, err = r.ReadLine()
        }
    
        // program completes normally...s
    }
    

    This is a second version with the scanner, and it uses both and ? as line delimiters:

    package main
    
    import (
        "bufio"
        "bytes"
        "fmt"
        "log"
        "os/exec"
    )
    
    // Ugly hack, this is bufio.ScanLines with ? added as an other delimiter :D
    func new_scanner(data []byte, atEOF bool) (advance int, token []byte, err error) {
        if atEOF && len(data) == 0 {
            return 0, nil, nil
        }
        if i := bytes.IndexByte(data, '
    '); i >= 0 {
            // We have a full newline-terminated line.
            fmt.Printf("nn
    ")
            return i + 1, data[0:i], nil
        }
        if i := bytes.IndexByte(data, '?'); i >= 0 {
            // We have a full ?-terminated line.
            return i + 1, data[0:i], nil
        }
        // If we're at EOF, we have a final, non-terminated line. Return it.
        if atEOF {
            return len(data), data, nil
        }
        // Request more data.
        return 0, nil, nil
    }
    
    func main() {
    
        cmd := exec.Command("rm", "-i", "somefile.txt")
    
        // Stdout + stderr
        out, err := cmd.StderrPipe() // Again, rm writes prompts to stderr
        if err != nil {
            log.Fatal(err)
        }
    
        scanner := bufio.NewScanner(out)
        scanner.Split(new_scanner)
    
        // Stdin
        in, err := cmd.StdinPipe()
        if err != nil {
            log.Fatal(err)
        }
        defer in.Close()
    
        // Start the command!
        err = cmd.Start()
        if err != nil {
            log.Fatal(err)
        }
    
        // Start scanning
        for scanner.Scan() {
            line := scanner.Text()
            if line == "rm: remove regular empty file ‘somefile.txt’" {
                in.Write([]byte("y
    "))
            }
        }
        // Report scanner's errors
        if err := scanner.Err(); err != nil {
            log.Fatal(err)
        }
    
        // program completes normally...s
    }
    
    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论

报告相同问题?

悬赏问题

  • ¥35 引用csv数据文件(4列1800行),通过高斯-赛德尔法拟合曲线,在选取(每五十点取1点)数据,求该数据点的曲率中心。
  • ¥20 程序只发送0X01,串口助手显示不正确,配置看了没有问题115200-8-1-no,如何解决?
  • ¥15 Google speech command 数据集获取
  • ¥15 vue3+element-plus页面崩溃
  • ¥15 像这种代码要怎么跑起来?
  • ¥15 安卓C读取/dev/fastpipe屏幕像素数据
  • ¥15 pyqt5tools安装失败
  • ¥15 mmdetection
  • ¥15 nginx代理报502的错误
  • ¥100 当AWR1843发送完设置的固定帧后,如何使其再发送第一次的帧