在Go中使用壳管

在命令行中成为好公民意味着使用管道。

使用竖线|我们可以将一个命令的输出作为另一个命令的输入来传递,并链接多个命令以提供唯一的输出。

我制作了2个使用管道作为输入的教程,建立了古柯赛戈洛尔卡特,但是我没有详细描述从管道获取输入的过程,因此这里是有关此主题的文章。

这是一个例子:

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>])
}

}

让我们研究一下它是如何工作的。第一条有趣的线:

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

os.Stdin像Stdout和Stderr一样,是开放的文件。它指向标准输入文件描述符。

Stat()是File的方法,该方法返回一个文件信息描述文件,提供包括模式和文件大小的信息。

下一个有趣的部分是

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

FileInfo.Mode()返回uint32将文件模式和权限确定为const的掩码(https://golang.org/pkg/os/#FileMode)。

Usign按位与并确定文件模式是否为os.ModeCharDevice。这是确保文件指向ModeCharDevice,Unix字符设备(终端)。由于文件指向os.Stdin,我们基本上排除了输入是管道的情况。

如果模式是不是我们通过的常数。我们也可以检查

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

相同,但更具可读性。

如果这是错误的,我们将另外检查

info.Size() <= 0

与上一个检查结合使用,请确保具有输入管道,并且该管道实际上包含一些字节。

我们也可以检查

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

并确保输入来自管道。

接下来,程序创建一个阅读器

reader := bufio.NewReader(os.Stdin)

bufio是一个实现缓冲I / O的程序包,基本上是包装io.Readerio.Writer

我们要求它使用默认的缓冲区大小(即4096字节)为os.Stdin提供一个缓冲的读取器。

bufio.Reader提供了许多读取数据的方法:ReadByteReadBytesReadLineReadRuneReadSliceReadString

该示例使用ReadRune因此可以将每个符文添加到var output []rune切片和处理统一码字符不费吹灰之力。

阅读更多


更多教程: