Skip to content

Commit aeb55ef

Browse files
committed
Add Detect If Stdin Comes From A Redirect as a Go TIL
1 parent a92af09 commit aeb55ef

File tree

2 files changed

+61
-1
lines changed

2 files changed

+61
-1
lines changed

README.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ pairing with smart people at Hashrocket.
1010

1111
For a steady stream of TILs, [sign up for my newsletter](https://crafty-builder-6996.ck.page/e169c61186).
1212

13-
_1541 TILs and counting..._
13+
_1542 TILs and counting..._
1414

1515
---
1616

@@ -405,6 +405,7 @@ _1541 TILs and counting..._
405405
- [Build For A Specific OS And Architecture](go/build-for-a-specific-os-and-architecture.md)
406406
- [Check If Cobra Flag Was Set](go/check-if-cobra-flag-was-set.md)
407407
- [Combine Two Slices](go/combine-two-slices.md)
408+
- [Detect If Stdin Comes From A Redirect](go/detect-if-stdin-comes-from-a-redirect.md)
408409
- [Do Something N Times](go/do-something-n-times.md)
409410
- [Find Executables Installed By Go](go/find-executables-installed-by-go.md)
410411
- [Format Date And Time With Time Constants](go/format-date-and-time-with-time-constants.md)
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
# Detect If Stdin Comes From A Redirect
2+
3+
Reading lines of input from `stdin` is flexible. And we may need our program to
4+
behave differently depending on where that input is coming from. For instance,
5+
if data is redirected or piped to our program, we scan and process it directly.
6+
Otherwise, we need to prompt the user to enter in specific info and go from
7+
there.
8+
9+
We can detect whether [`os.Stdin`](https://pkg.go.dev/os#pkg-variables) is
10+
being piped to, redirected to, or whether we should prompt the user by looking
11+
at the file mode descriptor of
12+
[`os.Stdin.Stat()`](https://pkg.go.dev/os#File.Stat).
13+
14+
```go
15+
package main
16+
17+
import (
18+
"bufio"
19+
"fmt"
20+
"os"
21+
)
22+
23+
func main() {
24+
file, err := os.Stdin.Stat()
25+
if err != nil {
26+
fmt.Printf("Error checking stdin: %v\n", err)
27+
os.Exit(1)
28+
}
29+
30+
fromTerminal := (file.Mode() & os.ModeCharDevice) != 0
31+
fromAPipe := (file.Mode() & os.ModeNamedPipe) != 0
32+
33+
if fromTerminal {
34+
fmt.Println("This is Char Device mode, let's prompt user for input")
35+
termScanner := bufio.NewScanner(os.Stdin)
36+
for termScanner.Scan() {
37+
fmt.Printf("- %s\n", termScanner.Text())
38+
break;
39+
}
40+
} else if fromAPipe {
41+
fmt.Println("This is Named Pipe mode, contents piped in")
42+
pipeScanner := bufio.NewScanner(os.Stdin)
43+
for pipeScanner.Scan() {
44+
fmt.Printf("- %s\n", pipeScanner.Text())
45+
}
46+
} else {
47+
fmt.Println("This means the input was redirected")
48+
redirectScanner := bufio.NewScanner(os.Stdin)
49+
for redirectScanner.Scan() {
50+
fmt.Printf("- %s\n", redirectScanner.Text())
51+
}
52+
}
53+
}
54+
```
55+
56+
If `os.ModeCharDevice` then we are connected to a character device, like the
57+
terminal. We can see if input is being piped in by checking against
58+
`os.ModeNamedPipe`. Otherwise, there are a variety of file modes and I'm
59+
willing to assume we're dealing with a regular file redirect at that point.

0 commit comments

Comments
 (0)