Use shell and tube in Go

Being a good citizen on the command line means using pipes.

Use vertical bars|We can pass the output of one command as the input of another command and chain multiple commands to provide a unique output.

I made 2 tutorials using pipes as input, and establishedCocossewithGorolkat, But I did not describe in detail the process of getting input from the pipeline, so here is an article on this topic.

This is an example:

package main

import ( “bufio” “fmt” “io” “os” )

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

<span style="color:#66d9ef">if</span> <span style="color:#a6e22e">info</span>.<span style="color:#a6e22e">Mode</span>()<span style="color:#f92672">&amp;</span><span style="color:#a6e22e">os</span>.<span style="color:#a6e22e">ModeCharDevice</span> <span style="color:#f92672">!=</span> <span style="color:#ae81ff">0</span> <span style="color:#f92672">||</span> <span style="color:#a6e22e">info</span>.<span style="color:#a6e22e">Size</span>() <span style="color:#f92672">&lt;=</span> <span style="color:#ae81ff">0</span> {
	<span style="color:#a6e22e">fmt</span>.<span style="color:#a6e22e">Println</span>(<span style="color:#e6db74">"The command is intended to work with pipes."</span>)
	<span style="color:#a6e22e">fmt</span>.<span style="color:#a6e22e">Println</span>(<span style="color:#e6db74">"Usage: fortune | gocowsay"</span>)
	<span style="color:#66d9ef">return</span>
}

<span style="color:#a6e22e">reader</span> <span style="color:#f92672">:=</span> <span style="color:#a6e22e">bufio</span>.<span style="color:#a6e22e">NewReader</span>(<span style="color:#a6e22e">os</span>.<span style="color:#a6e22e">Stdin</span>)
<span style="color:#66d9ef">var</span> <span style="color:#a6e22e">output</span> []<span style="color:#66d9ef">rune</span>

<span style="color:#66d9ef">for</span> {
	<span style="color:#a6e22e">input</span>, <span style="color:#a6e22e">_</span>, <span style="color:#a6e22e">err</span> <span style="color:#f92672">:=</span> <span style="color:#a6e22e">reader</span>.<span style="color:#a6e22e">ReadRune</span>()
	<span style="color:#66d9ef">if</span> <span style="color:#a6e22e">err</span> <span style="color:#f92672">!=</span> <span style="color:#66d9ef">nil</span> <span style="color:#f92672">&amp;&amp;</span> <span style="color:#a6e22e">err</span> <span style="color:#f92672">==</span> <span style="color:#a6e22e">io</span>.<span style="color:#a6e22e">EOF</span> {
		<span style="color:#66d9ef">break</span>
	}
	<span style="color:#a6e22e">output</span> = append(<span style="color:#a6e22e">output</span>, <span style="color:#a6e22e">input</span>)
}

<span style="color:#66d9ef">for</span> <span style="color:#a6e22e">j</span> <span style="color:#f92672">:=</span> <span style="color:#ae81ff">0</span>; <span style="color:#a6e22e">j</span> &lt; len(<span style="color:#a6e22e">output</span>); <span style="color:#a6e22e">j</span><span style="color:#f92672">++</span> {
	<span style="color:#a6e22e">fmt</span>.<span style="color:#a6e22e">Printf</span>(<span style="color:#e6db74">"%c"</span>, <span style="color:#a6e22e">output</span>[<span style="color:#a6e22e">j</span>])
}

}

Let's study how it works. The first interesting line:

info, err := os.Stdin.Stat()

os.StdinLike Stdout and Stderr, it is openfile. It points to the standard input file descriptor.

Stat()Is the method of File, the method returns aFile informationThe description file provides information including the mode and file size.

The next interesting part is

info.Mode()&os.ModeCharDevice != 0

FileInfo.Mode()returnuint32The file mode and permissions are determined as a const mask (https://golang.org/pkg/os/#FileMode).

Usign bitwise AND determines whether the file mode is os.ModeCharDevice. This is to make sure the file points toModeCharDevice, Unix character device (terminal). As the file points toos.Stdin, We basically rule out the case where the input is a pipe.

If the mode isIs notThe constant we passed. We can also check

info.Mode()&os.ModeCharDevice == os.ModeCharDevice

The same, but more readable.

If this is wrong, we will additionally check

info.Size() <= 0

In combination with the previous check, make sure you have an input pipe, and that pipe actually contains some bytes.

We can also check

if info.Mode()&os.ModeNamedPipe != 0 {
	// we have a pipe input
}

And make sure that the input comes from the pipeline.

Next, the program creates a reader

reader := bufio.NewReader(os.Stdin)

bufioIs a package that implements buffered I/O, basically a packageio.Readerwithio.Writer.

We require it to use the default buffer size (ie 4096 bytes) to provide a buffered reader for os.Stdin.

bufio.ReaderProvides many ways to read data:ReadByte,ReadBytes,ReadLine,ReadRune,ReadSlice,ReadString.

This example usesReadRuneSo you can add each rune tovar output []runeSlicing and processingUnicodeThe characters are effortless.

read more


More tutorials: