Uso de Shell Pipes con Go

Ser un buen ciudadano en la línea de comando significa usar tuberías.

Usando la barra vertical|podemos pasar la salida de un comando como entrada de otro comando y encadenar varios comandos para proporcionar una salida única.

He hecho 2 tutoriales que usan tuberías como entrada, construyendogocowsayygololcat, pero no describí en detalle el proceso para obtener información de una tubería, así que aquí hay un artículo sobre este tema.

He aquí un ejemplo:

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

}

Examinemos cómo funciona esto. Primera línea interesante:

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

os.Stdin, como Stdout y Stderr, es unaArchivo. Apunta al descriptor de archivo de entrada estándar.

Stat()es un método de archivo que devuelve unInformación del archivodescribiendo el archivo, proporcionando información que incluye el modo y el tamaño del archivo.

La siguiente pieza interesante es

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

FileInfo.Mode()devuelve eluint32máscara que determina el modo de archivo y los permisos como const (https://golang.org/pkg/os/#FileMode).

Use un Y determina si el modo de archivo es os.ModeCharDevice. Esta es una forma de asegurarse de que el archivo apunte a unModeCharDevice, el dispositivo de caracteres Unix (terminal). Dado que el archivo apunta aos.StdinBásicamente, excluimos que la entrada sea una tubería.

Bitwise devuelve 0 si el modo esnola constante que pasamos. También podríamos comprobar

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

eso es lo mismo, pero más legible.

Si esto es falso, tenemos una verificación adicional para

info.Size() <= 0

que combinado con la verificación anterior, se asegura de tener una tubería de entrada, y que en realidad contiene algunos bytes.

También podríamos comprobar

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

y esto asegurará que la entrada provenga de la tubería.

A continuación, el programa crea un lector.

reader := bufio.NewReader(os.Stdin)

bufioes un paquete que implementa E / S con búfer, básicamente envolviendoio.Readeryio.Writer.

Le pedimos que nos dé un lector con búfer de os.Stdin, usando el tamaño de búfer predeterminado que es 4096 bytes.

bufio.Readerproporciona muchos métodos para leer datos:ReadByte,ReadBytes,ReadLine,ReadRune,ReadSlice,ReadString.

El ejemplo usaReadRunepara que pueda agregar cada runa leída en elvar output []runecortar y manipularUnicodechars sin ningún esfuerzo.

Leer más


Más tutoriales de go: