2014-12-05 42 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

相關問題