Как передать трубку в программу Go? - PullRequest
0 голосов
/ 02 ноября 2018

Я хочу написать небольшую программу Go, которую я могу использовать для украшения данных JSON. Это уже работает, когда я использую файл. Вот код:

package main

import (
    "bufio"
    "fmt"
    "github.com/Jeffail/gabs"
    "log"
    "os"
)

func main() {
    info, err := os.Stdin.Stat()
    if err != nil {
        log.Fatal(err)
    }

    if info.Mode()&os.ModeCharDevice != 0 || info.Size() <= 0 {
        fmt.Println("The command is intended to work with pipes.")
        fmt.Println("cat file.json | prettyjson")
        return
    }

    reader := bufio.NewReader(os.Stdin)


    input, err := reader.ReadBytes('\n')
    if err != nil {
        log.Fatal()
    }

    jsonParsed, err := gabs.ParseJSON(input)
    if err != nil {
        log.Fatal("couldn't parse json")
    }

    fmt.Println(fmt.Println(jsonParsed.StringIndent("", "  ")))
}

Если я запускаю этот код с помощью curl, как это:

curl -s "https://min-api.cryptocompare.com/data/top/exchanges?fsym=BTC&tsym=USD" | prettyjson

Я получаю: (23) Failed writing body

Я видел в этом посте , что канал закрывается до того, как curl сможет записать все данные, но как мне оптимизировать мою программу Go для ожидания завершения скручивания?

1 Ответ

0 голосов
/ 02 ноября 2018

Что касается исходного кода OP, я бы подумал об изменении условия для обнаружения присутствия канала.

Как уже указано в https://stackoverflow.com/a/43947435/4466350, правильное условие не требует проверки длины входа. Думая об этом, это имеет смысл, так как вы можете открыть stdin без записи данных на него.

Кроме того, предлагаемое решение кажется бесполезно сложным для достижения того, чего оно пытается добиться, красивой печати ввода json.

Я обнаружил, что использования стандартной библиотеки было достаточно для достижения цели для данного теста.

По поводу вопроса ...but how do I optimize my Go program to wait until curl is done?, похоже, что OP не понимает, как работают файловые дескрипторы. На самом деле вопрос даже не правильный, так как процесс теоретически может остаться в живых, но активно решено закрыть Stdin. OP не заинтересован в оживлении процесса, вместо этого он должен просто искать сигнал EOF при чтении Stdin, указывая, что интересные данные были отправлены правильно.

В любом случае, простое решение выглядит следующим образом: оборачивайте stdin с помощью json-декодера, зацикливайтесь до тех пор, пока eof или не произойдет ошибка, для каждой декодированной информации закодируйте ее в json с помощью обертки stdout при повторном прерывании ошибки.

package main

import (
    "encoding/json"
    "fmt"
    "io"
    "log"
    "os"
)

func main() {
    info, err := os.Stdin.Stat()
    if err != nil {
        log.Fatal(err)
    }

    if info.Mode()&os.ModeCharDevice != 0 {
        fmt.Println("The command is intended to work with pipes.")
        fmt.Println("cat file.json | prettyjson")
        return
    }

    dec := json.NewDecoder(os.Stdin)
    enc := json.NewEncoder(os.Stdout)
    enc.SetIndent("", "  ")

    for {
        data := map[string]interface{}{}
        if err := dec.Decode(&data); err != nil {
            if err == io.EOF {
                break
            }
            log.Fatalf("decode error %v", err)
        }
        if err := enc.Encode(data); err != nil {
            log.Fatalf("encod error %v", err)
        }
    }
}
...