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

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.


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.

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.