在Go语言中,如何区分终端输入和管道输入?

简要概括

在创建CLI时,由于需要区分来自终端的输入和来自管道处理的输入,因此需要整理记录。

目录
1. 源代码
2. 执行结果
3. 原理和实现细节
4. 参考文献

源代码

package main

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

    "golang.org/x/crypto/ssh/terminal"
)

const (
    TERMINAL = "terminal"
    PIPE     = "pipe"
)

func main() {
    isTerminal := terminal.IsTerminal(int(os.Stdin.Fd()))
    switch isTerminal {
    case true:
        var stdin string
        fmt.Scan(&stdin)
        fmt.Printf("type: %s, text: %s\n", TERMINAL, stdin)
        break
    case false:
        stdin, _ := ioutil.ReadAll(os.Stdin)
        fmt.Printf("type: %s, text: %s", PIPE, string(stdin))
        break
    default:
    }
}

运行结果

确认一下实际输入是否能够进行区分。

如果是终端输入的情况下

请通过键盘输入 “hoge” 作为标准输入

$: go run .\main.go
hoge 
type: terminal, text: hoge

如果采用管道输入的情况

通过管道的标准输入,在命令行中输入” hoge”。

$: echo hoge | go run .\main.go
type: pipe, text: hoge

原理与实现细节

为什么要进行上述实施?

在管道处理中,os.Stdin不是终端输入。
在管道处理中,os.Stdin并非终端输入。
在管道处理中,os.Stdin不是来自终端的输入。

當執行golang的可執行檔時,操作系統會啟動一個進程來執行它。此時,stdin(/dev/stdin)默認接受來自鍵盤的輸入,因此stdin被視為來自終端的輸入。然而,當golang的可執行檔作為管道處理從其他進程執行時,該golang進程中的stdin(/dev/stdin)不再來自鍵盤,而是接受來自另一個進程(在終端上看,這是管道符號左側命令的進程)的輸出。換句話說,它不再是從鍵盤輸入的。而且,golang的os.Stdin被註冊為/dev/stdin的文件描述符。

通过使用IsTerminal,判断给定的文件描述符是否来自终端输入。

当给IsTerminal方法传递terminal包的IsTerminal参数,并调用时,它能够判断它是否来自键盘输入。因此,这次我将os.Stdin.Fd()作为参数传递并调用,以表示stdin的文件描述符。通过这样做,我能区分来自终端还是管道的输入。

文献引用

    • プロセス・パイプ・リダイレクション・ファイルディスクリプタの実体を見に行く

 

    • osパッケージ

 

    terminalパッケージ
广告
将在 10 秒后关闭
bannerAds