Golang io.Copy блоков во внутреннем ReadFrom - PullRequest
0 голосов
/ 21 октября 2019

Я создаю эмулятор терминала в golang, и я пытался запустить отдельные процессы, из которых я могу скопировать вывод и отобразить его пользователю, но функциональные блоки io.Copy, и, следовательно, я не могу перейти к выходной части

Я посмотрел исходный код, и он блокируется во внутреннем методе ReadFrom, я не могу понять, почему это происходит

package main

import (
    "bytes"
    "fmt"
    "io"
    "os"
)

func main() {
    inputReader, inputWriter, _ := os.Pipe()
    outputReader, outputWriter, _ := os.Pipe()

    io.Copy(inputWriter, bytes.NewReader([]byte("\n")))

    stdin := inputReader
    stdout := outputWriter
    stderr := outputWriter

    var attr = os.ProcAttr{
        Dir: "/tmp",
        Env: nil,
        Files: []*os.File{
            stdin,
            stdout,
            stderr,
        },
        Sys: nil,
    }

    process, startProcessErr := os.StartProcess("/usr/bin/ls", []string{"ls"}, &attr)
    if startProcessErr != nil {
        panic(startProcessErr)
    }

    if releaseProcessErr := process.Release(); releaseProcessErr != nil {
        panic(releaseProcessErr)
    }

    var output bytes.Buffer
    io.Copy(&output, outputReader)
    fmt.Println(output)
}

Может быть, это потому, что я выпускаю процесс, но я не думаю, что это должно произойти

1 Ответ

4 голосов
/ 21 октября 2019

Вызов io.Copy(&output, outputReader) блокируется до тех пор, пока чтение outputReader не вернет EOF или какую-либо другую ошибку. Чтение outputReader не возвращает EOF, потому что сторона записи канала все еще открыта в родительском процессе. Исправьте, закрыв средство записи в родительском процессе.

...

if releaseProcessErr := process.Release(); releaseProcessErr != nil {
    panic(releaseProcessErr)
}

outputWriter.Close() // <-- add this line

var output bytes.Buffer
io.Copy(&output, outputReader)
fmt.Println(output)

...

Используйте пакет os / exec для упрощения кода:

cmd := exec.Command("/usr/bin/ls")
cmd.Dir = "/tmp"
output, err := cmd.CombinedOutput()
if err != nil {
    log.Fatal(err)
}
fmt.Println(string(output))
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...