通过SSH传输Stdout和Stderr,操纵流,然后打印到本地Stdout和Stderr

时间:2019-01-24 00:16:13

标签: go streaming stdout stderr channels

我正在远程计算机上通过SSH执行一堆操作,并且正在流式传输其stdout和stderr,然后由写入器将其使用,写入器将其与字节缓冲区一起写入本地stdout和stderr。 / p>

就在作者使用它之前,我想对其进行一系列字符串操作,然后将其写入屏幕和缓冲区。到此为止,一切都正常且花哨。

我的问题是现在它不再是流,它会挂起,然后将整个glob分成一个块输出。我希望它是实时的,因此我将频道添加到我的执行例程中,但没有任何改善。以下是我的功能,请告诉我您是否可以找到原因,或者可能是实现此目的的更好方法。

//发送

func handleStdStream(filters []string, replaceFilters map[string]string, pipe io.Reader, readers chan io.Reader) {
        if filters != nil {
                // filters exist
                // read first 8 bytes
                res := readPipe(8, pipe)

                // get each line from the resulting streamed output
                for _, str := range strings.Split(res, "\n") {
                        if str != "" {
                                out := lineFilterAndReplace(str, filters, replaceFilters)

                                // instantiate an io.Reader obj from the given string
                                outReader := strings.NewReader(out)

                                readers <- outReader
                        }
                }
        } else {
                // filters dont exist
                if len(replaceFilters) > 0 {
                        res := readPipe(8, pipe)

                        for _, str := range strings.Split(res, "\n") {
                                if str != "" {
                                        out := lineReplace(str, replaceFilters)

                                        // instantiate an io.Reader obj from the given string
                                        outReader := strings.NewReader(out)

                                        readers <- outReader
                                }
                        }
                } else {
                        readers <- pipe
                }
        }
}

//正在接收

    outReaders := make(chan io.Reader)

    go handleStdStream(outFilters, replaceFilters, stdoutIn, outReaders)

    go func() {
            for {
                    pipe := <-outReaders

                    _, errStdout = io.Copy(outWriter, pipe)
            }

            // _, errStdout = io.Copy(outWriter, stdoutIn)
    }()

1 个答案:

答案 0 :(得分:1)

我认为您不需要渠道或goroutine来完成此任务。 WriterReader接口已经在流化;您连续从Reader读取字节,直到遇到EOF或错误,然后连续将字节交给Writer直到完成或出现错误。就其本身而言,处理流不需要任何并发性,因此在单个goroutine中按顺序执行此操作非常合适。

您不应忽略错误返回。如果函数或方法返回错误值,则需要检查它。对于I / O,通常会在返回错误时停止从Reader读取,而在返回错误时通常需要停止向Writer写入。对于Reader,还必须检查特殊的“错误”值io.EOF

我认为使用Scanner包中的bufio比尝试自己进行缓冲/拆分要好。默认情况下,Scanner在换行符上分割输入(Unix样式的LF或DOS样式的CRLF)。如果您仅通过io.EOFReader进行交互,那么它也无需检查Scanner

请考虑以下handleStdStream版本:

func handleStdStream(filters []string, replaceFilters map[string]string, pipe io.Reader, w io.Writer) error {
    scanner := bufio.NewScanner(pipe)
    for scanner.Scan() {
        str := scanner.Text()
        if str == "" {
            continue
        }
        out := ""
        if len(filters) != 0 {
            out = lineFilterAndReplace(str, filters, replaceFilters)
        } else {
            out = lineReplace(str, replaceFilters)
        }
        if _, err := w.Write([]byte(out)); err != nil {
            return err
        }
    }
    if err := scanner.Err(); err != nil {
        return err
    }
    return nil
}

您将像这样使用它:

err := handleStdStream(filters, replaceFilters, pipe, outWriter)
if err != nil {
    // do something, like printing the error to a log or stderr
}