Skip to content

Latest commit

 

History

History
59 lines (51 loc) · 1.77 KB

detect-if-stdin-comes-from-a-redirect.md

File metadata and controls

59 lines (51 loc) · 1.77 KB

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 is being piped to, redirected to, or whether we should prompt the user by looking at the file mode descriptor of os.Stdin.Stat().

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.