From aeb55efc3c4e48652ae9039aaa2dc223c30ad92c Mon Sep 17 00:00:00 2001 From: jbranchaud Date: Wed, 18 Dec 2024 11:05:29 -0600 Subject: [PATCH] Add Detect If Stdin Comes From A Redirect as a Go TIL --- README.md | 3 +- go/detect-if-stdin-comes-from-a-redirect.md | 59 +++++++++++++++++++++ 2 files changed, 61 insertions(+), 1 deletion(-) create mode 100644 go/detect-if-stdin-comes-from-a-redirect.md diff --git a/README.md b/README.md index f8f0055..5bfb9d6 100644 --- a/README.md +++ b/README.md @@ -10,7 +10,7 @@ pairing with smart people at Hashrocket. For a steady stream of TILs, [sign up for my newsletter](https://crafty-builder-6996.ck.page/e169c61186). -_1541 TILs and counting..._ +_1542 TILs and counting..._ --- @@ -405,6 +405,7 @@ _1541 TILs and counting..._ - [Build For A Specific OS And Architecture](go/build-for-a-specific-os-and-architecture.md) - [Check If Cobra Flag Was Set](go/check-if-cobra-flag-was-set.md) - [Combine Two Slices](go/combine-two-slices.md) +- [Detect If Stdin Comes From A Redirect](go/detect-if-stdin-comes-from-a-redirect.md) - [Do Something N Times](go/do-something-n-times.md) - [Find Executables Installed By Go](go/find-executables-installed-by-go.md) - [Format Date And Time With Time Constants](go/format-date-and-time-with-time-constants.md) diff --git a/go/detect-if-stdin-comes-from-a-redirect.md b/go/detect-if-stdin-comes-from-a-redirect.md new file mode 100644 index 0000000..eea99b6 --- /dev/null +++ b/go/detect-if-stdin-comes-from-a-redirect.md @@ -0,0 +1,59 @@ +# Detect If Stdin Comes From A Redirect + +Reading lines of input from `stdin` is flexible. And we may need our program to +behave differently depending on where that input is coming from. For instance, +if data is redirected or piped to our program, we scan and process it directly. +Otherwise, we need to prompt the user to enter in specific info and go from +there. + +We can detect whether [`os.Stdin`](https://pkg.go.dev/os#pkg-variables) is +being piped to, redirected to, or whether we should prompt the user by looking +at the file mode descriptor of +[`os.Stdin.Stat()`](https://pkg.go.dev/os#File.Stat). + +```go +package main + +import ( + "bufio" + "fmt" + "os" +) + +func main() { + file, err := os.Stdin.Stat() + if err != nil { + fmt.Printf("Error checking stdin: %v\n", err) + os.Exit(1) + } + + fromTerminal := (file.Mode() & os.ModeCharDevice) != 0 + fromAPipe := (file.Mode() & os.ModeNamedPipe) != 0 + + if fromTerminal { + fmt.Println("This is Char Device mode, let's prompt user for input") + termScanner := bufio.NewScanner(os.Stdin) + for termScanner.Scan() { + fmt.Printf("- %s\n", termScanner.Text()) + break; + } + } else if fromAPipe { + fmt.Println("This is Named Pipe mode, contents piped in") + pipeScanner := bufio.NewScanner(os.Stdin) + for pipeScanner.Scan() { + fmt.Printf("- %s\n", pipeScanner.Text()) + } + } else { + fmt.Println("This means the input was redirected") + redirectScanner := bufio.NewScanner(os.Stdin) + for redirectScanner.Scan() { + fmt.Printf("- %s\n", redirectScanner.Text()) + } + } +} +``` + +If `os.ModeCharDevice` then we are connected to a character device, like the +terminal. We can see if input is being piped in by checking against +`os.ModeNamedPipe`. Otherwise, there are a variety of file modes and I'm +willing to assume we're dealing with a regular file redirect at that point.