2017-08-28 72 views
2

我必須處理腳本的長輸出並找到一些數據。這些數據很可能位於輸出的最開始處。數據發現後,我不需要處理輸出,可以退出。如何強制golang關閉打開的管道

由於exec.Cmd沒有關閉打開的命令的功能,所以無法停止處理輸出的問題。

這裏有一些簡單的代碼(錯誤處理是中省略):

func processOutput(r *bufio.Reader)(){ 
    for { 
     line, _, err := r.ReadLine() 
     if some_condition_meet { 
     break 
     } 
     ...... 
    } 
    return 
} 

func execExternalCommand(){ 
    cmdToExecute := "......" 
    cmd := exec.Command("bash", "-c", cmdToExecute) 
    output, _ := cmd.StdoutPipe() 

    cmd.Start() 
    r := bufio.NewReader(output) 
    go processOutput(r) 
    cmd.Wait() 
    return 
} 

我目前應該做到底在processOutput功能停止在cmd?也許有另一種方法來解決它。

感謝

+0

你是什麼意思,沒有辦法「關閉打開的命令」?你可以通過發送一個信號退出來終止一個進程,你可以通過'Kill'​​或'Signal'方法來完成這個過程。 – JimB

+0

如果該命令讀取stdin並在EOF上退出,則關閉stdin至該命令。否則,發送其他評論中提到的信號。 –

+0

只需添加更多細節,如果關閉stdin,那麼子進程的stdout寫入將導致它接收到一個SIGPIPE信號(默認情況下,除非這種行爲被覆蓋)。所以你發送信號的方式是這樣或那樣。 –

回答

3

既然這樣,你不能從processOutput,因爲它接受所有是bufio.Reader做到這一點。您需要將exec.Cmd傳遞給它,以便它對分叉進程執行任何操作。

要殺死分叉進程,可以發送一個信號,例如:cmd.Process.Kill()cmd.Process.Signal(os.SIGINT)。請參閱關於exec.Cmdos.Process的文檔。

+0

感謝您的指導 – ravnur

1

你也許可以用「context」,例如:

package main 

import (
    "bufio" 
    "context" 
    "os/exec" 
) 

func processOutput(r *bufio.Reader, cancel context.WithCancel) { 
    for { 
     line, _, err := r.ReadLine() 
     if some_condition_meet { 
      break 
     } 
    } 
    cancel() 
    return 
} 

func main() { 
    ctx, cancel := context.WithCancel(context.Background()) 
    defer cancel() 
    cmdToExecute := "......" 
    cmd := exec.CommandContext(ctx, "bash", "-c", cmdToExecute) 
    output, _ := cmd.StdoutPipe() 

    cmd.Start() 
    r := bufio.NewReader(output) 
    go processOutput(r, cancel) 
    cmd.Wait() 
    return 
} 

如果需要,以結束與超時這可能是工作(例如從這裏取:https://golang.org/src/os/exec/example_test.go

func ExampleCommandContext() { 
    ctx, cancel := context.WithTimeout(context.Background(), 100*time.Millisecond) 
    defer cancel() 

    if err := exec.CommandContext(ctx, "sleep", "5").Run(); err != nil { 
    // This will fail after 100 milliseconds. The 5 second sleep 
    // will be interrupted. 
    } 
    } 

基本示例只是使用睡眠,但在1秒後關閉它:https://play.golang.org/p/gIXKuf5Oga

+1

這個答案是黃金,它應該是最好的答案。 – tahoe