views:

202

answers:

5

Is there a case of ... or context where cat file | ... behaves differently than ... <file?

A: 

cat file | starts up another program (cat) that doesn't have to start in the second case. It also makes it more confusing if you want to use "here documents". But it should behave the same.

Paul Tomblin
+4  A: 

cat will allow you to pipe multiple files in sequentially. Otherwise, < redirection and cat file | produce the same side effects.

spoulson
+6  A: 

When reading from a regular file, cat is in charge of reading the data, performs it as it pleases, and might constrain it in the way it writes it to the pipeline. Obviously, the contents themselves are preserved, but anything else could be tainted. For example: block size and data arrival timing. Additionally, the pipe in itself isn't always neutral: it serves as an additional buffer between the input and ....

Quick and easy way to make the block size issue apparent:

$ cat large-file | pv >/dev/null
5,44GB 0:00:14 [ 393MB/s] [              <=>                                  ]
$ pv <large-file >/dev/null
5,44GB 0:00:03 [1,72GB/s] [=================================>] 100%
JB
Interesting, although given that read() uses a finite buffer, either way you'll hit some processes minimum buffer size. strace shows that cat uses 32kB reads and pv 128kB on my platform.
msw
Oh, hey, my example doesn't actually match the question, since I'm not using < with pv. Re-running...
JB
@msw it'll get *very* dependent on the implementation of `cat`, but I'll try to make it apparent in a different way.
JB
+1  A: 

Pipes cause a subshell to be invoked for the command on the right. This interferes with environment variables.

cat foo | while read line
do
  ...
done
echo "$line"

versus

while read line
do
  ...
done < foo
echo "$line"
Ignacio Vazquez-Abrams
Both gave the same results when I tried them.
JB
interesting side effect.
pra
@JB: Set a variable inside the loop, then echo it after the loop. The changed value will only persist after the redirected form and won't after the piped form. Another demonstration is to `cd` inside the loop and `pwd` after the loop.
Dennis Williamson
+2  A: 

Besides the thing posted by other users, when using input redirection from a file, standard input is the file but when piping the output of cat to the input, standard input is a stream with the contents of the file. When standard input is the file will be able to seek within the file but the pipe will not allow it. You can see this by finding a zip file and running the following commands:

zipinfo /dev/stdin < thezipfile.zip

and

cat thezipfile.zip | zipinfo /dev/stdin

The first command will show the contents of the zipfile while the second will show an error, though it is a misleading error because zipinfo does not check the result of the seek call and errors later on.

Geoff Reedy