4

Yes, I have already tried looking it up elsewhere, but the examples which are supposed to illustrate input redirection, like here for example, always have one confusing caveat. In the example of the site just posted, they say:

  # echo 'hello world' >output
  # cat <output

The first line writes "hello world" to the file "output", the second reads it back and writes it to standard output (normally the terminal).

However, cat output would do the exact same thing, no noeed for < here. So what is the difference??

5

Input redirection (as in cat < file) means the shell is opening the input file and writing its contents to the standard input of another process. Passing the file as an argument (as you do when running cat file) means the program you are using (e.g. cat) needs to open the file itself and read the contents.

Basically, command file passes a file to command while command < file passes the contents of a file to command. Yes, in cases like cat file vs cat < file there is no easily perceived difference in outcome, but but the two work in different ways.

To understand the difference, think of a young child and an adult. Both of them can drink water. However, the adult can open the tap and fill a glass (open the file and read its contents) while the child needs the water to be given to it directly (it can't open the file and can only process its contents).

Some programs, like cat, are capable of taking a filename as input and then opening the file and doing their thing on it. That's why cat file works. Other programs, however, don't have any knowledge of what files are or how to use them. All they know about is input streams (like the file's contents). For example, tr:

$ cat file
foo
$ cat file | tr 'o' 'b'  ## tr can read a stream
fbb
$ tr 'o' 'b' file  ## tr can't deal with files
tr: extra operand ‘file’
Try 'tr --help' for more information.
$ tr 'o' 'b' < file ## input redirection!
fbb

Another example is ls which can deal with files just fine, but ignores input streams:

$ ls
file1  file2
$ ls file1   ## lists only file1: ls takes file names as arguments
file1
$ ls < file1 ## ls ignores its standard input, this is the same as ls alone
file1 file2

Other programs can't deal with streams and instead require files:

$ rm < file ## fails, rm needs a file 
rm: missing operand
Try 'rm --help' for more information.
$ rm file ## works, file is deleted

Some programs can deal with both opening files and reading input streams but behave in different ways with each. For example, wc which, when given a file to open, prints the name of the file as well as the number of lines, words and characters:

$ wc file
1 1 4 file

But, if we just give it a stream, it has no way of knowing that this is coming from a specific file so no file name is printed:

$ wc < file
1 1 4

The md5sum command behaves similarly:

$ md5sum file
17fd54512c91e3cd0f70fbaaa9a94d0d  file
$ md5sum < file
17fd54512c91e3cd0f70fbaaa9a94d0d  - 

Note that in the first case the file name file is shown while, in the second, "filename" is -: standard input.


Now, if you want more gritty details, you can use strace to see exactly what's going on:

strace -e trace=open,close,read,write wc file 2>strace1.txt

and

strace -e trace=open,close,read,write wc < file 2>strace2.txt

Those will have all the details of all open(), close() and read() operations run by the process. What you want to see is that strace1.txt (when the file was passed as an argument and not with input redirection) contains these lines:

open("file", O_RDONLY)                  = 3
read(3, "foo\n", 16384)                 = 4

Those mean that the file file was opened and attached to the file descriptor 3. Then, the string foo\n was read from 3. The equivalent part of the strace output when using input redirection is:

read(0, "foo\n", 16384)                 = 4

There is no corresponding open() call, instead the string foo\n is being read from 0, the standard input1.


1 By default, 0 is standard input, 1 is standard output and 2 is standard error. This, by the way, is why file was opened as 3, that was the next available one.

  • "the shell is opening the input file and writing its contents to the standard input of another process" -- I'm not sure if this was meant as a lie to children, but of course the shell doesn't read or write anything from the file involved in a redirection, it just opens it for the started process to read or write. – ilkkachu Jul 21 at 15:02
  • @ilkkachu how else would you describe the difference between wc file and wc < file? I mean that in the case of wc < file, wc is not aware of any file; the file handling is done by the shell. On the other hand, when running wc file, the file handing is done by wc. – terdon Jul 22 at 8:29
  • but the shell doesn't read or write anything, it just opens the file for wc to read. Sure, in the case of wc file, wc has to do the opening too, but that's distinct from the actual data flow. Well, it looks like I'm just repeating myself, which is probably because I just don't know how to phrase this in any other way. "opening the file and writing its contents to stdin of another process" sounds more like cat file | another process than another process < file (cat does read and write tha data) – ilkkachu Jul 22 at 8:31
  • @ilkkachu let's take this to chat. – terdon Jul 22 at 8:40
1

Basically the differences are:

  1. cat output.txt: reads the contents of output.txt file to standard output directly

  2. cat < output.txt: the output (or contents) of output.txt via the redirect standard input symbol (<) is read by the cat command. Hence output.txt is used an input for < command.

The output for both methods will be the same but an extra path is taken in the second method as a result of the < redirect standard input symbol.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.