A Proper CLI
Flags with defaults, an exit code returned through a run() helper so defers still run, and stdin detection that tells a terminal from a pipe. Try it plain, with -name Go -upper, or piped: echo hi | go run ..
package main
import (
"bufio"
"flag"
"fmt"
"os"
"strings"
)
func main() {
os.Exit(run())
}
// run returns an exit code; keeping os.Exit at the edge lets defers fire.
func run() int {
upper := flag.Bool("upper", false, "uppercase the greeting")
name := flag.String("name", "world", "who to greet")
flag.Parse()
greeting := "hello, " + *name
if *upper {
greeting = strings.ToUpper(greeting)
}
fmt.Println(greeting) // hello, world
// Is stdin a terminal or a pipe? Check the ModeCharDevice bit.
info, _ := os.Stdin.Stat()
if (info.Mode() & os.ModeCharDevice) == 0 {
fmt.Println("stdin is piped; echoing lines:")
sc := bufio.NewScanner(os.Stdin)
for sc.Scan() {
fmt.Println(" |", sc.Text())
}
} else {
fmt.Println("stdin is a terminal (try: echo hi | go run .)")
}
return 0
}Save the code as main.go and try it a few ways:
go run main.go # defaults
go run main.go -name Go -upper # flags
echo hi | go run main.go # pipe into stdinDefault output:
hello, world
stdin is a terminal (try: echo hi | go run .)Piping input instead detects the pipe and echoes each line:
hello, world
stdin is piped; echoing lines:
| hi