3

grep and sed ignore stdin if you provide a filename parameter:

$ echo foo > test.txt
$ echo foobar | grep f test.txt 
foo
$ echo foobar | sed -e 's/foo/bar/' test.txt 
bar

Is this established best practice? If so, why?

l0b0
  • 51,350
  • generally if your program can support both then foo filename - for both filename and stdin(the -), only read from stdin if you are told to OR no filename is provided. – cjh Dec 30 '12 at 01:31

2 Answers2

1

The Answer I found is that's how it is designed. If you want to read from both stdin and file use echo foobar | grep f - test.txt. from man grep

 grep  searches the named input FILEs (or standard input if no files are
 named, or if a single hyphen-minus (-) is given as file name) for lines
 containing  a  match to the given PATTERN.  By default, grep prints the
 matching lines.
1

A program knows whether files are specified on its command line. It cannot know whether there is any input available on stdin (other than by trying to read it), and if there is input, there is no way for the program to know whether that input was intended for it. So the only sensible option is to have a clear rule, based on how the program was invoked (command line arguments, environment variables, configuration files, …), to decide whether it will read from stdin or not.

For example, typical text utilities (cat, sort, grep, awk, perl -p, …) read from stdin if no file is provided, and read from the specified file(s) if there are any. Interpreters obey a similar convention, for example sh with no arguments reads commands from standard input while sh script_file_name reads commands from the specified file (and leaves stdin to be read by the script if it wants). There is also a common convention that if - appears in a position where the name of an input file is expected, the program will read from stdin.

Consider a shell snippet like

somecommand | while read line; do
  process "$line"
done

You need to know whether process reads from stdin or not. There's no such thing as “testing whether stdin is provided”: it's there, but the user who invokes the program knows whether he wants stdin to be read or not.