在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パッケージ