What is the difference between "cat < filename" and "cat filename"?

Solution 1:

cat file

The cat program will open, read and close the file.

cat < file

Your shell will open the file and connect the contents to cat's stdin. cat recognizes it has no file arguments, and will read from stdin.

Solution 2:

There is no difference from a user point of view. These commands do the same thing.

Technically the difference is in what program opens the file: the cat program or the shell that runs it. Redirections are set up by the shell, before it runs a command.

(So in some other commands--that is, not the command shown in the question--there may be a difference. In particular, if you can't access file.txt but the root user can, then sudo cat file.txt works but sudo cat < file.txt does not.)

You can use either one that is convenient in your case.

There are almost always many ways to get the same result.

cat accepts a file from arguments or stdin if there are no arguments.

See man cat:

SYNOPSIS
       cat [OPTION]... [FILE]...

DESCRIPTION
       Concatenate FILE(s) to standard output.

       With no FILE, or when FILE is -, read standard input.

Solution 3:

One Big Difference

One big difference is with the *, ?, or [ globbing characters (wildcards) or anything else the shell may expand into multiple filenames. Anything the shell expands into two or more items, rather than treating as a single filename, cannot be opened for redirection.

Without redirection (ie no <), the shell passes multiple filenames to cat, which outputs the files' contents one after another. For example this works:

$ ls hello?.py
hello1.py  hello2.py

$ cat hello?.py

# Output for two files 'hello1.py' and 'hello2.py' appear on your screen

But with redirection (<) an error message occurs:

$ ls < hello?.py
bash: hello?.py: ambiguous redirect

$ cat < hello?.py
bash: hello?.py: ambiguous redirect

One Tiny Difference

I thought with redirection it would be slower but there is no perceivable time difference:

$ time for f in * ; do cat "$f" > /dev/null ; done

real    0m3.399s
user    0m0.130s
sys     0m1.940s

$ time for f in * ; do cat < "$f" > /dev/null ; done

real    0m3.430s
user    0m0.100s
sys     0m2.043s

Notes:

  • The difference is about 1/1000th (1 one thousandth) of a second in this test. In other tests it was 1/100th of a second which is still can't be noticed.
  • Alternate the tests a few times so data is cached into RAM as much as possible and more consistent comparison times are returned. Another option is to drop all caches before each test.