Подтвердить что ты не робот

Проверьте, есть ли что-то для чтения на STDIN в Голанге

Мне нужна утилита командной строки, чтобы вести себя по-другому, если какая-то строка передана в его STDIN. Вот несколько минимальных примеров:

package main // file test.go

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

func main() {
    bytes, _ := ioutil.ReadAll(os.Stdin)

    if len(bytes) > 0 {
        fmt.Println("Something on STDIN: " + string(bytes))
    } else {
        fmt.Println("Nothing on STDIN")
    }
}

Это отлично работает, если вы так называете:

echo foo | go run test.go

Если test.go вызывается без каких-либо изменений на STDIN, вещь стягивается...

bytes, _ := ioutil.ReadAll(os.Stdin)

... ждет EOF.

Что мне нужно сделать, чтобы это произошло?

Спасибо заранее!

4b9b3361

Ответ 1

Я решил это, используя os.ModeCharDevice:

stat, _ := os.Stdin.Stat()
if (stat.Mode() & os.ModeCharDevice) == 0 {
    fmt.Println("data is being piped to stdin")
} else {
    fmt.Println("stdin is from a terminal")
}

Ответ 2

Используйте IsTerminal функцию code.google.com/p/go.crypto/ssh/terminal (который был exp/terminal) или функция Isatty из github.com/andrew-d/go-termutil  который представляет собой гораздо более целенаправленный пакет.

Если stdin - это терминал /tty, тогда вы не являетесь файлом, и вы можете сделать что-то другое.

Вот пример

package main

import (
    "fmt"
    "github.com/andrew-d/go-termutil"
    "io"
    "os"
)

func main() {
    if termutil.Isatty(os.Stdin.Fd()) {
        fmt.Println("Nothing on STDIN")
    } else {
        fmt.Println("Something on STDIN")
        io.Copy(os.Stdout, os.Stdin)
    }
}

Тестирование

$ ./isatty 
Nothing on STDIN
$ echo "hello" | ./isatty 
Something on STDIN
hello
$ (sleep 1 ; echo "hello") | ./isatty 
Something on STDIN
hello

Ответ 3

Если ни одно из вышеперечисленных действий для вас не работает, выполните следующие действия:

stat, err := os.Stdin.Stat()
if err != nil {
    return nil, fmt.Errorf("you have an error in stdin:%s", err)
}
if (stat.Mode() & os.ModeNamedPipe) == 0 {
    return nil, errors.New("you should pass smth to stdin")
}

Он работал у меня как в darwin (Mac OS), так и в Linux (Ubuntu).

Ответ 4

Это делает:

package main // file test.go

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

func main() {
    in := bufio.NewReader(os.Stdin)
    stats, err := os.Stdin.Stat()
    if err != nil {
        fmt.Println("file.Stat()", err)
    }

    if stats.Size() > 0 {
        in, _, err := in.ReadLine()
        if err != nil {
            fmt.Println("reader.ReadLine()", err)
        }
        fmt.Println("Something on STDIN: " + string(in))
    } else {
        fmt.Println("Nothing on STDIN")
    }
}

Спасибо @Kluyg!