Hi, I have a small program to read stdin and execute some commands accordingly.
It s composed of a for loop which waits for data to read on the source. I found out i could quit the loop by closing its source and catching err on ReadString calls to skip the iteration. Qs are, - is there a cleaner and cheap way to handle reader close ? Or in my case properly get away from the loop. - Aside from the previous, How can i use err to detect a closed resource ? The error i get is "read /dev/stdin: bad file descriptor" I mean something like described in Dave C last talk. In practical terms, how to get an identifier for the err, how to compare it. The specific part of the code looks likes this, func StdinRead (cmds map[string]func([]string), unhandled *func([]string)) { reader := bufio.NewReader(os.Stdin) for { text, err := reader.ReadString('\n') if err!=nil { fmt.Printf("%+v\n", err) continue } text = strings.TrimSpace(text) args := strings.Split(text, " ") if len(args)<1 { continue } if fn, ok := cmds[args[0]]; ok { fn(args[1:]) } else if unhandled!=nil { h := *unhandled h(args) } else { fmt.Printf("unhandled: '%s' %v\n", args[0], args[1:]) } } } func StdinQuit () { fmt.Println("Quiting the app, see you!") os.Stdin.Close() // force close stdin, otherwise the process hangs in the next for loop time.Sleep(time.Second * 200) } The full one file reproducible example is, package main import( "fmt" "bufio" "strings" "os" "os/signal" "syscall" "time" ) func main () { EOApp := Quiter{} go EOApp.Read() cmds := make(map[string] func([]string)) cmds["hello"] = func (s []string) { fmt.Println("hello buddy!") } cmds["serve"] = func (s []string) { // fmt.Println("hello buddy!") } cmds["ping"] = func (s []string) { // fmt.Println("hello buddy!") } unhandled := func (s []string) { if s[0]!="" { fmt.Printf("nop, i don t know this command: '%s' %v\n", s[0], s[1:]) } } EOApp.Register(StdinQuit) StdinRead(cmds, &unhandled) } func StdinRead (cmds map[string]func([]string), unhandled *func([]string)) { reader := bufio.NewReader(os.Stdin) for { text, err := reader.ReadString('\n') if err!=nil { fmt.Printf("%+v\n", err) continue } text = strings.TrimSpace(text) args := strings.Split(text, " ") if len(args)<1 { continue } if fn, ok := cmds[args[0]]; ok { fn(args[1:]) } else if unhandled!=nil { h := *unhandled h(args) } else { fmt.Printf("unhandled: '%s' %v\n", args[0], args[1:]) } } } func StdinQuit () { fmt.Println("Quiting the app, see you!") os.Stdin.Close() // force close stdin, otherwise the process hangs in the next for loop time.Sleep(time.Second * 200) } type Quiter struct { Components []func() } func (q *Quiter) Register (component func()) int { q.Components = append(q.Components, component) return len(q.Components)-1 } func (q *Quiter) exitComponents () { for _, component := range q.Components { component() } } func (q *Quiter) Read () { c := make(chan os.Signal) signal.Notify(c, os.Interrupt, syscall.SIGTERM) signalSent := 0 for { select { case <-c: if signalSent <1 { go func () { q.exitComponents() os.Exit(1) }() } else { fmt.Println("Force shutdown") os.Exit(1) } signalSent++ } } } BTW, do i need to make a unbuffered chan of len 2 in Quiter.Read func to catch both signals appropriately ? I don t really get the implications of the doc when it says, Package signal will not block sending to c: the caller must ensure that c has sufficient buffer space to keep up with the expected signal rate. For a channel used for notification of just one signal value, a buffer of size 1 is sufficient. thks -- You received this message because you are subscribed to the Google Groups "golang-nuts" group. To unsubscribe from this group and stop receiving emails from it, send an email to golang-nuts+unsubscr...@googlegroups.com. For more options, visit https://groups.google.com/d/optout.