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
  • 4
  • 11
FuRinKaZan_001
  • 118
  • 1
  • 7
  • 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 '20 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? – FuRinKaZan_001 Jan 25 '20 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 '20 at 18:00
  • 1
    Relating https://unix.stackexchange.com/q/337739/117549 – Jeff Schaller Jan 25 '20 at 18:05
  • Similar: [When should I use input redirection?](//unix.stackexchange.com/q/70756) – Stéphane Chazelas Jun 22 '23 at 05:22

2 Answers2

0

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
  • 669
  • 4
  • 6
  • 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 ` – Kamil Maciorowski Jun 22 '23 at 04:17
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нιη
  • 40,939
  • 15
  • 71
  • 114
  • 1
    Standard compliant `grep`s 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