Home > Blockchain >  How to read and format a stream of text received through a bash pipe?
How to read and format a stream of text received through a bash pipe?

Time:01-21

Currently, I'm using the following to format data from my npm script.

npm run startWin | while IFS= read -r line; do printf '%b\n' "$line"; done | less

It works, but my colleagues do not use Linux. So, I would like to implement while IFS= read -r line; do printf '%b\n' "$line"; done in Go, and use the binary in the pipe.

npm run startWin | magical-go-formater

What I tried

package main

import (
    "fmt"
    "io/ioutil"
    "os"
    "strings"
)

func main() {
  fi, _ := os.Stdin.Stat() // get the FileInfo struct

  if (fi.Mode() & os.ModeCharDevice) == 0 {

    bytes, _ := ioutil.ReadAll(os.Stdin)
    str := string(bytes)
    arr := strings.Fields(str)

    for _, v := range arr {
      fmt.Println(v)
    }
}

Currently the program silences any output from the text-stream.

CodePudding user response:

@Sandy Cash was helpful in stating to use Bufio. I don't know why, if what @Jim said is true, but Bufio worked out and ReadAll() didn't.

Thanks for the help.

The code:

package main

import (
    "bufio"
    "fmt"
    "os"
    "strings"
)

func main() {
    scanner := bufio.NewScanner(os.Stdin)
    for scanner.Scan() {
        s := scanner.Text()
        arr := strings.Split(s, `\n`)
        for _, v := range arr {
            fmt.Println(string(v))
        }
    }
}

CodePudding user response:

You want to use bufio.Scanner for tail-type reads. IMHO the checks you're doing on os.Stdin are unnecessary, but YMMV.

See this answer for an example. ioutil.ReadAll() (now deprecated, just use io.ReadAll()) reads everything there is to read when it's called - and at that point in time, there's a good likelihood that npm hasn't written anything onto the pipe yet. ReadAll() is a one time "gimme everything you got", not a looping input - that's why you want bufio.Scanner.Scan().

Also - %b will convert any escape sequence in the text - e.g. any \n in a passed line will be rendered as a newline - do you need that? B/c go does not have an equivalent format specifier, AFAIK.

  • Related