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?

tchrist
  • 433

2 Answers2

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)

tansy
  • 741
  • 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. – Kamil Maciorowski Jun 22 '23 at 04: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 08 '23 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

αғsнιη
  • 41,407
  • 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. – Stéphane Chazelas Jun 22 '23 at 05:21