So you need concurrent input from Stdin (pipe) and user Stdin (Keyboard):
i think you answer is cat command see: How can I pipe initial input into process which will then be interactive?
and: https://en.wikipedia.org/wiki/Cat_(Unix)
see: How to pipe several commands in Go?
and Go Inter-Process Communication
there are 3 things to note:
first: it is good practice to check for all errors:
in your case :
n, err := fmt.Scanln(&response)
second:
you are using recursive call (Tail Call) and it is not necessary here.
replace it with simple for loop and see: Tail Call Optimization in Go
3rd:
last but not least: in case of bad input your code loops for ever(consuming stack if compiler could not optimizes tail call)!
it is good to limit to 3.
example:
package main
import "fmt"
import "strings"
type Input int
const (
Timeout Input = iota
Yes
No
Abort
BadInput
)
func userInput(msg string) Input {
var input string
for i := 0; i < 3; i++ {
fmt.Println(msg)
n, err := fmt.Scanln(&input)
if n > 0 {
switch strings.ToLower(input) {
case "y":
return Yes
case "n":
return No
case "a":
return Abort
}
}
if err != nil {
return BadInput // or panic(err)
}
}
return Timeout
}
func main() {
ans := userInput("Please type Yes,No or Abort and then press enter [y/n/a]: ")
fmt.Println(ans)
switch ans {
case Yes:
fmt.Println("Yes") // do some job
//...
}
}
Edit:
with this simple "y/n" you do not need to check is it pipe or not.
even simple std Read with one byte slice is good:
os.Stdin.Read(b1)
see my piping sample: https://stackoverflow.com/a/37334984/6169399
but in case your Stdin is pipe you may use:
bytes, err := ioutil.ReadAll(os.Stdin)
to read all piped data all at once. but be careful to handle errors.
you can check if stdin is associated with a terminal or a pipe then use appropriate code.
simple way to detect it is pipe or not :
package main
import (
"fmt"
"os"
)
func main() {
info, err := os.Stdin.Stat()
if err != nil {
fmt.Println("not a pipe")
} else {
fmt.Println("pipe name=", info.Name(), "pipe size=", info.Size())
}
}
all in one sample code:
package main
import (
"fmt"
"io/ioutil"
"os"
"strings"
)
type Input int
const (
Timeout Input = iota
Yes
No
Abort
BadInput
)
func userInput(msg string) Input {
var input string
for i := 0; i < 3; i++ {
fmt.Println(msg)
n, err := fmt.Scanln(&input)
if n > 0 {
switch strings.ToLower(input) {
case "y":
return Yes
case "n":
return No
case "a":
return Abort
}
}
if err != nil {
return BadInput // or panic(err)
}
}
return Timeout
}
func main() {
info, err := os.Stdin.Stat()
if err != nil {
//fmt.Println("not a pipe")
ans := userInput("Please type Yes,No or Abort and then press enter [y/n/a]: ")
fmt.Println(ans)
switch ans {
case Yes:
fmt.Println("Yes") // do some job
//...
}
} else {
fmt.Println("pipe name=", info.Name(), "pipe size=", info.Size())
bytes, err := ioutil.ReadAll(os.Stdin)
fmt.Println(string(bytes), err) //do some jobe with bytes
}
}