当标准输入为管道时如何从设备读取
How to read from device when stdin is pipe
所以我有一个从 STDIN 读取的 Go 程序,如下所示。我希望从键盘或设备输入用户名和密码,但可以使用管道传递字符串切片。如果我 运行 命令如下:
echo "Hello World" | go run main.go
os.Stdin
将设置为从管道读取,而不是从键盘读取。有没有一种方法可以更改 os.Stdin
FileMode,使其从设备读取,即用户名和密码的键盘?
我尝试使用 os.Stdin.Chmod(FileMode)
但收到此错误:
chmod /dev/stdin: invalid argument
func main() {
var n = []string{}
scanner := bufio.NewScanner(os.Stdin)
fmt.Println("Please type anything with Newline Separated, empty line signals termination")
for scanner.Scan() {
h := scanner.Text()
if h == "" {
break
}
n = append(n, h)
}
if err := scanner.Err(); err != nil {
fmt.Printf("Error in reading from STDIN: %v\n", err)
}
reader := bufio.NewReader(os.Stdin)
os.Stdout.WriteString("Username: ")
username, err := reader.ReadString('\n')
if err != nil {
fmt.Printf("Unable to read username: %v\n", err)
}
username = strings.TrimSpace(username)
os.Stdout.WriteString("Password: ")
bytePassword, _ := terminal.ReadPassword(int(os.Stdin.Fd()))
password := string(bytePassword)
os.Stdout.WriteString("\n")
}
可能 scanf 可以提供帮助,请查看此示例:
https://play.golang.org/p/tteQNl0trJp
package main
import (
"fmt"
)
func main() {
fmt.Println("Enter your name")
var name string
fmt.Scanf("%s", &name)
fmt.Printf("name = %s\n", name)
}
检查是否有可从 stdin 读取的内容,如果没有则提示用户:
https://play.golang.org/p/7qeAQ5UNhdQ
package main
import (
"bufio"
"fmt"
"log"
"os"
)
func main() {
// check if there is somethinig to read on STDIN
stat, _ := os.Stdin.Stat()
if (stat.Mode() & os.ModeCharDevice) == 0 {
var stdin []byte
scanner := bufio.NewScanner(os.Stdin)
for scanner.Scan() {
stdin = append(stdin, scanner.Bytes()...)
}
if err := scanner.Err(); err != nil {
log.Fatal(err)
}
fmt.Printf("stdin = %s\n", stdin)
} else {
fmt.Println("Enter your name")
var name string
fmt.Scanf("%s", &name)
fmt.Printf("name = %s\n", name)
}
}
您可以改为从 /dev/tty
读取,因为这始终是终端(如果程序在终端上运行)。这仅适用于 Unix-like 系统(Linux、BSD、macOS 等),不适用于 Windows。
// +build !windows
tty, err := os.Open("/dev/tty")
if err != nil {
log.Fatalf("can't open /dev/tty: %s", err)
}
scanner := bufio.NewScanner(tty)
// as you were ...
所以我有一个从 STDIN 读取的 Go 程序,如下所示。我希望从键盘或设备输入用户名和密码,但可以使用管道传递字符串切片。如果我 运行 命令如下:
echo "Hello World" | go run main.go
os.Stdin
将设置为从管道读取,而不是从键盘读取。有没有一种方法可以更改 os.Stdin
FileMode,使其从设备读取,即用户名和密码的键盘?
我尝试使用 os.Stdin.Chmod(FileMode)
但收到此错误:
chmod /dev/stdin: invalid argument
func main() {
var n = []string{}
scanner := bufio.NewScanner(os.Stdin)
fmt.Println("Please type anything with Newline Separated, empty line signals termination")
for scanner.Scan() {
h := scanner.Text()
if h == "" {
break
}
n = append(n, h)
}
if err := scanner.Err(); err != nil {
fmt.Printf("Error in reading from STDIN: %v\n", err)
}
reader := bufio.NewReader(os.Stdin)
os.Stdout.WriteString("Username: ")
username, err := reader.ReadString('\n')
if err != nil {
fmt.Printf("Unable to read username: %v\n", err)
}
username = strings.TrimSpace(username)
os.Stdout.WriteString("Password: ")
bytePassword, _ := terminal.ReadPassword(int(os.Stdin.Fd()))
password := string(bytePassword)
os.Stdout.WriteString("\n")
}
可能 scanf 可以提供帮助,请查看此示例:
https://play.golang.org/p/tteQNl0trJp
package main
import (
"fmt"
)
func main() {
fmt.Println("Enter your name")
var name string
fmt.Scanf("%s", &name)
fmt.Printf("name = %s\n", name)
}
检查是否有可从 stdin 读取的内容,如果没有则提示用户:
https://play.golang.org/p/7qeAQ5UNhdQ
package main
import (
"bufio"
"fmt"
"log"
"os"
)
func main() {
// check if there is somethinig to read on STDIN
stat, _ := os.Stdin.Stat()
if (stat.Mode() & os.ModeCharDevice) == 0 {
var stdin []byte
scanner := bufio.NewScanner(os.Stdin)
for scanner.Scan() {
stdin = append(stdin, scanner.Bytes()...)
}
if err := scanner.Err(); err != nil {
log.Fatal(err)
}
fmt.Printf("stdin = %s\n", stdin)
} else {
fmt.Println("Enter your name")
var name string
fmt.Scanf("%s", &name)
fmt.Printf("name = %s\n", name)
}
}
您可以改为从 /dev/tty
读取,因为这始终是终端(如果程序在终端上运行)。这仅适用于 Unix-like 系统(Linux、BSD、macOS 等),不适用于 Windows。
// +build !windows
tty, err := os.Open("/dev/tty")
if err != nil {
log.Fatalf("can't open /dev/tty: %s", err)
}
scanner := bufio.NewScanner(tty)
// as you were ...