2014-12-05 50 views
1

我需要能够运行外部应用程序并与其交互,就像我从命令行手动运行它一样。我发现的所有例子只涉及运行程序和捕获输出。与代码内的外部应用程序交互(Golang)

下面是一个非常简单的例子,我希望说明我正在努力完成什么。

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... 

} 

我试图调整我已经发现的各种例子,取得零成功。看起来,即使'rm'正在等待回应,Go会关闭这个过程。

任何您可以提供的示例,文章或建议将不胜感激。提前谢谢了。

+0

未验证的,但我认为['cmd.Std {IN,OUT,ERR}管()'](http://golang.org/pkg/os/exec/#Cmd.StderrPipe )(在'cmd.Start()')和['cmd.Wait()']之前(http://golang.org/pkg/os/exec/#Cmd.Wait)。您可能必须阅读其答复,然后才能与其进行更多互动。 – twotwotwo 2014-12-05 18:57:59

+1

为什么不先删除somefile.txt,然后运行你的命令?或者,是否要将执行的程序的输出附加到somefile.txt? – Dippo 2014-12-05 19:21:58

回答

1

你有两种可能性。首先是使用ReadLine(),但只有在应用程序输出为全行时才有效,并且您可以等待\ n。 rm并非如此,因此您必须为Scanner开发自定义SplitFunction。这两个版本都可以在下面找到。

请注意,您无法使用CombinedOutput,因为它无法被扫描。你必须使用管道。

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\n")) 
     } 
     line, _, err = r.ReadLine() 
    } 

    // program completes normally...s 
} 

这是扫描仪的第二个版本,它同时使用\ n和?如线分隔符:

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, '\n'); i >= 0 { 
     // We have a full newline-terminated line. 
     fmt.Printf("nn\n") 
     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\n")) 
     } 
    } 
    // Report scanner's errors 
    if err := scanner.Err(); err != nil { 
     log.Fatal(err) 
    } 

    // program completes normally...s 
} 
+0

我知道它说避免说'谢谢',但这是一个很好的答案,它的工作原理与广告一样。正是我所需要的。我将学习你的代码。 – 2014-12-05 22:07:42

+0

@briannewman说实话,我也不知道如何解决这个问题。我试图回答这个网站上的问题来学习我自己!你做得越多,你就越好。很高兴我有帮助:) – user918176 2014-12-05 22:09:40

相关问题