cat just regurgitates the contents of the file, but the resulting piped fd is non-seekable. Since almost every command that can operate on a file from stdin can also operate on the file by name/path, at best this is just a needless invocation of a process (i.e. `tv foo.csv` should have been used instead of `cat foo.csv | tv`) - if the app in question can't handle paths, then you can have the shell pipe the file into it instead (e.g. `tv < foo.csv`). At worst, the recipient program would need to buffer the entire contents of the input if it needs to perform non-sequential operations on the source data - this is the case with things like `tac` that need to seek to the end of the input (see https://github.com/neosmart/tac for how `cat foo | tac` requires buffering but both `tac foo` and even `tac < foo` don't).
To some, it's a faux-pas. Personally, I like the aesthetics of cat for my own scripts. It follows the "pipe flowing" idiom better.
There are performance reasons why "useless cat" should be avoided though. So avoid it where performance is important (or when some other hardcore CLI jockey is going to see your code :))
Avoiding “useless cat” on the command line is premature optimization. Sure, don’t do it in a script that is invoked a lot but it shouldn’t be a concern when prototyping a filter pipeline.
$ cat foo | head -4
b
a
c
b
$ cat foo | head -4 | sort
a
b
b
c
$ cat foo | head -4 | sort | uniq -c
1 a
2 b
1 c
$ cat foo | head -4 | sort | uniq -c | sort -k1nr | head -1
2 b