golang: se divertindo com os.Stdin e shell pipes

Como podemos saber quando nosso aplicativo tem um stdin canalizado ou não?

os.Pipeé um os.Filepara que possamos usar File.Stat()qual return a os.FileInfoe podemos usar FileInfo.Size()para ver se há algum dado disponível para leitura.

package main

import (
"os"
"fmt"
)

func main
() {
fi, err := os.Stdin.Stat()
if err != nil {
panic
(err)
}
if fi.Size() > 0 {
fmt
.Println("there is something to read")
} else {
fmt
.Println("stdin is empty")
}
}

Isso funcionará com, $ date | go run main.gomas não $ curl http://www.google.com/ | go run main.go.

Como curlprecisamos de algum tempo para enviar dados, sempre teremos 0 (zero) para FileInfo.Size().

Para fazer funcionar, temos que usar FileInfo.Mode().

package main

import (
"os"
"fmt"
)

func main
() {
fi, err := os.Stdin.Stat()
if err != nil {
panic
(err)
}
fmt
.Printf("%vn", fi.Mode())
}
$ go run main.go
Dcrw--w----
$ date | go run main.go
prw
-rw----

O que é isso?

File.Mode()retornar uma FileModebandeira.

Você pode ver o que é cada letra aqui FileMode .

A bandeira que procuramos é os.ModeNamedPipe. Quando esta bandeira está ativada , significa que temos um tubo.

package main

import (
"os"
"fmt"
)

func main
() {
fi, err := os.Stdin.Stat()
if err != nil {
panic
(err)
}
if fi.Mode() & os.ModeNamedPipe == 0 {
fmt
.Println("no pipe :(")
} else {
fmt
.Println("hi pipe!")
}
}

Desta forma, podemos saber quando nosso comando está recebendo stdout de outro processo.

Se você tiver alguma outra ideia comente.

Você pode comentar sobre meus erros de inglês também para que eu possa aprender.

Obrigado.