2017-08-28 6 views
2

私はスクリプトの長い出力を処理してデータを見つけなければなりません。このデータは、出力のほぼ初めに位置する可能性が最も高いです。データが見つかったら、出力をもう処理する必要はなく、終了することができます。開かれたパイプを閉じるためにgolangを強制する方法

exec.Cmdには開かれたコマンドを閉じる機能がないため、出力処理を停止できないという問題があります。ここで

は、いくつかの単純化されたコード(エラーハンドリングがommitedた)次のとおりです。

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 
} 

私はcmdを停止するprocessOutput機能で最後に何をすべきでしょうか?多分それを解決する別の方法があります。

おかげ

+0

「開かれたコマンドを閉じる」方法はありません。プロセスを終了させるには、 'Kill'​​メソッドまたは' Signal'メソッドで行うことができます。 – JimB

+0

コマンドがstdinを読み取り、EOFで終了した場合は、stdinをコマンドに閉じます。それ以外の場合は、他のコメントに記載されているように信号を送信してください。 –

+0

少し詳細を追加するだけで、stdinを閉じると、サブプロセスのstdoutはSIGPIPEシグナルを受け取るようになります(この動作がオーバーライドされない限り、デフォルトで)。だからあなたは、ある方法や別の方法で信号を送信しています。 –

答えて

3

現状では、受信するすべてのbufio.Readerですので、あなたがprocessOutputからこれを行うことはできません。フォークされたプロセスで何かを行うには、exec.Cmdを渡す必要があります。

フォークされたプロセスを強制終了するには、シグナルを送信します(例:cmd.Process.Kill()またはcmd.Process.Signal(os.SIGINT))。 exec.Cmdおよびos.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

関連する問題