0

When I use my shell’s redirection operator to provide a (non-existent) filename to the grep command, the error message about that file not existing is displayed by my shell. But when I provide that same filename as an argument to the grep command, the corresponding error message is displayed by the grep command itself. Why is that?

Here’s a demonstration of what I’m talking about. When I run the command:

$ grep 'root' /etc/passw

I get the following error message:

grep: /etc/passw: No such file or directory

But when I run the command this way with shell redirection:

$ grep 'root' < /etc/passw

I instead get the following error message:

bash: /etc/passw: No such file or directory

What is the difference between these two methods of specifying the input filename, and is there any significance in having them behave this way?

5
  • 1
    The redirection is done by bash so it makes sense that bash errors in that case. Otherwise grep itself tries to read from the file. The way that the two differ varies from utility to utility.
    – jesse_b
    Jan 25, 2020 at 17:55
  • @jesse_b Hi, thank you for your answer. I assumed it would be the case, is there any significant difference between the two ways of providing input? Jan 25, 2020 at 17:57
  • 1
    @FuRinKaZan_001: For some things (like wc) there is a significant difference, I'm sure there are more examples as well I just can't think of them right now.
    – jesse_b
    Jan 25, 2020 at 18:00
  • 1
    Relating unix.stackexchange.com/q/337739/117549
    – Jeff Schaller
    Jan 25, 2020 at 18:05

2 Answers 2

1

In your first command ($ grep 'root' /etc/passw) you give argument/s to grep and it interprets it as file name and searches for it. It (grep) fails so communicates you what happened. It is grep that interprets your input and acts on it.

In your second command (grep 'root' < /etc/passw) you make shell (here: bash) to pipe /etc/passw to standard input of grep. It (bash) cannot find it so it communicates you that. Here, it is bash that interprets your input and acts on it.

Second command is conceptual equivalent to $ bash-cat /etc/passw | grep 'root' where bash-cat would operate as cat which prints given file on standard output. Then it would be redirected to grep.

$ bash-cat /etc/passw | grep 'root'

bash-cat: /etc/passw: No such file or directory

--

If you read about pipes you will understand. (Pipes: A Brief Introduction)

2
  • 1
    "Second command is conceptual equivalent to $ bash-cat /etc/passw | grep 'root'" – Only in the context of opening the file, but not further. I mean in <passwd grep … the tool starts with its stdin redirected to a regular file. It can seek if it wants. In Linux it can open the same file for writing (by opening /dev/stdin). It can know the size of the file. There is nothing between grep and passwd, the shell does not act as a relay. Your bash-cat is a "relay", your grep reads from an unnamed pipe, it cannot do these things I mentioned. Jun 22 at 4:17
  • Maybe I overexplained this and made a mistake on the way. Maybe I should write an answer again, I simplests, possible way.
    – tansy
    Sep 8 at 18:10
0

When using I/O redirection operators like this, the shell itself opens the file for the input to the command as stdin with O_RDONLY on fd0 which commands can read only from it, but when passing as an argument, it’s the command itself which handles opening the file.

So if you have a program — let's say awk — and use < redirection to pass the filename, and you try to print FILENAME for which file it's opened, it will get reported - (meaning that input is stdin); see the following output:

awk '{ print FILENAME }' --infile
--infile

awk '{ print FILENAME }' <--infile
-

Another advantage is that if a filename starts with a hyphen, the shell will handle it itself, but if you pass as an argument to the command — say grep — it will complain because it think it's an invalid option provided.

grep root --infile
grep: unrecognized option '--infile'
Usage: grep [OPTION]... PATTERN [FILE]...
Try 'grep --help' for more information.

Standard, standards-compliant commands use -- to avoid this error by telling the command it’s the end of its option-argument. You can also provide either the absolute path of file or a relative path with ./--infle, or you let the shell open it for the command by using command <--infile.

note: Use of <inputfile command is the same variant of the command <inputfile.

another advantage is if that file was not exist or shell failed to open it, then your command will not execute.

awk 'BEGIN{ print "ifrun" }' < non-existing_file
-bash: non-existing_file: No such file or directory

awk 'BEGIN{ print "ifrun" }' non-existing_file
ifrun
1
  • 1
    Standard compliant greps have no problem with grep foo --infile. Like standard compliant awk's have no problem with awk 1 --infile. GNU grep does though when $POSIXLY_CORRECT is not in the environment, and some versions of busybox awk do. A file called - is also a problem whether -- is used or not. Jun 22 at 5:21

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .