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.