同时扫描stdout和stderr

时间:2017-10-02 00:04:02

标签: go exec stdout stderr

我正在寻找一种同时处理stdout和stderr作为一个流的方法。 对于stdout,我可以使用:

cmd := exec.Command(command, flags...)
var wg sync.WaitGroup

stdout, err := cmd.StdoutPipe()
if err != nil {
    return fmt.Errorf("RunCommand: cmd.StdoutPipe(): %v", err)
}

if err := cmd.Start(); err != nil {
    return fmt.Errorf("RunCommand: cmd.Start(): %v", err)
}

scanner := bufio.NewScanner(stdout)
scanner.Split(ScanLinesR)
wg.Add(1)
go func() {
    for scanner.Scan() {
        text := scanner.Text()
        if strings.TrimSpace(text) != "" {
            DoWhateverYouNeedWithText(text)
        }
    }
    wg.Done()
}()

wg.Wait()

但是我如何将stderr添加到相同的代码中?

2 个答案:

答案 0 :(得分:2)

如上所述,评论员建议我增加2个goroutine(一个用于stderr,一个用于关闭频道)。

--- switch_loadable_module.c    2017-07-13 20:07:30.000000000 +0800
+++ freeswitch-1.6.19/src/switch_loadable_module.c  2017-09-29 17:23:10.000000000 +0800
@@ -1875,15 +1875,6 @@

    if (!autoload) return SWITCH_STATUS_SUCCESS;

-   switch_loadable_module_load_module("", "CORE_SOFTTIMER_MODULE", SWITCH_FALSE, &err);
-   switch_loadable_module_load_module("", "CORE_PCM_MODULE", SWITCH_FALSE, &err);
-   switch_loadable_module_load_module("", "CORE_SPEEX_MODULE", SWITCH_FALSE, &err);
-#ifdef SWITCH_HAVE_YUV
-#ifdef SWITCH_HAVE_VPX
-   switch_loadable_module_load_module("", "CORE_VPX_MODULE", SWITCH_FALSE, &err);
-#endif
-#endif
-
    if ((xml = switch_xml_open_cfg(cf, &cfg, NULL))) {
        switch_xml_t mods, ld;
        if ((mods = switch_xml_child(cfg, "modules"))) {
@@ -1980,6 +1971,15 @@
        apr_dir_close(module_dir_handle);
    }

+   switch_loadable_module_load_module("", "CORE_SOFTTIMER_MODULE", SWITCH_FALSE, &err);
+   switch_loadable_module_load_module("", "CORE_PCM_MODULE", SWITCH_FALSE, &err);
+   switch_loadable_module_load_module("", "CORE_SPEEX_MODULE", SWITCH_FALSE, &err);
+#ifdef SWITCH_HAVE_YUV
+#ifdef SWITCH_HAVE_VPX
+   switch_loadable_module_load_module("", "CORE_VPX_MODULE", SWITCH_FALSE, &err);
+#endif
+#endif
+
    switch_loadable_module_runtime();

    memset(&chat_globals, 0, sizeof(chat_globals));

答案 1 :(得分:0)

// child.go

func main() {
    fmt.Fprintln(os.Stdout, "Child started.")
    time.Sleep(time.Second * 1)
    fmt.Println("Tick...")
    time.Sleep(time.Second * 1)
    fmt.Println("Tick...")
    time.Sleep(time.Second * 1)
    fmt.Println("Tick...")
    time.Sleep(time.Second * 2)
    fmt.Println("Child ended.")
}
// childerr.go
func main() {
    fmt.Fprintln(os.Stdout, "Child started.")
    time.Sleep(time.Second * 1)
    fmt.Fprintln(os.Stdout, "Tick...")
    time.Sleep(time.Second * 1)
    fmt.Fprintln(os.Stdout, "Tick...")
    time.Sleep(time.Second * 1)
    fmt.Fprintln(os.Stdout, "Tick...")
    time.Sleep(time.Second * 2)
    panic("testing")
    fmt.Fprintln(os.Stdout, "Child ended.")
}
func executeCommand(output chan<- string, err chan<- error, start chan interface{}, cmd *exec.Cmd) {

    defer close(start)

    stdout, e := cmd.StdoutPipe()
    if e != nil {
        log.Println("Error starting Cmd: ", e)
        err <- e
        return
    }

    cmd.Stderr = cmd.Stdout

    <-start

    scanner := bufio.NewScanner(stdout)

    for scanner.Scan() {
        output <- scanner.Text()
    }

}

func run(cmd *exec.Cmd) {

    start := make(chan interface{})
    output := make(chan string)
    errChan := make(chan error)
    defer close(output)
    defer close(errChan)

    go executeCommand(output, errChan, start, cmd)

    start <- nil

    if e := cmd.Start(); e != nil {
        log.Println("Error starting Cmd: ", e)
    }

    for {
        select {
        case b := <-output:
            fmt.Println(b)
        case e := <-errChan:
            fmt.Println("ERR EXECUTING COMMAND->", e)
            return
        case <-start:
            fmt.Println("COMPLETED")
            return
        }
    }
}

使用child或childerr创建长时间运行的样本。