Recently, I read on planet debian another rant along the lines of “why oh why do people use cat when they could just redirect from a file?” – but not that this is a new complaint from expert users.
I’ve got one big reason for using cat on the command-line: it’s far too easy to type gpg >encryptedfile when you mean gpg <encryptedfile and almost no systems have noclobber switched on by default any more, even on shells that support such an option. So you end up losing a valuable data file and having to recover it from backups – I’ve seen it happen too often.
Because the pipe symbol is nowhere near anything destructive, cat encryptedfile |gpg seems far less likely to end in tears, so I try not to criticise someone for doing that.
That doesn’t completely excuse using it in a script file, though, especially if it’s used lots.
Is there another way I’ve forgotten that would reduce the risk of a destructive typo in the redirection?
I have another – convenient – reason to use “cat file | …”. If I need to grep for different strings in a file it’s much more convenient to change the last word in the previous command line than a word in the middle:
grep some_string some_file
cat some_file | grep some_string
One handy use for cat is to force terminal-aware software to work in a non-terminal-aware way. For example, compare on a 80xSomething terminal, “dpkg -l” and “dpkg -l |cat”. The former will try to fit output into a terminal, and for me, has 30 lines of “ii xserver-xorg-v $someversion”. With “dpkg -l |cat”, I can actually tell apart the different xserver-xorg-v* packages.
another reason to use cat FILE | is to protect FILE from itself.
There are far too many console programms which would modifie the source file without special options or even delete it (eg. gzip, bzip, …)
another reason to use cat FILE | PROG is to protect FILE from PROG itself.
There are far too many console programms which would modifie the source file without special options or even delete it (eg. gzip, bzip, …)
ps.: sorry for the double post, special chars got filtered
Personally, I sometimes use cat for ad-hoc pipelines because it let’s me start at the beginning of the pipeline and finish at the end. It’s can also be more readable when giving examples, for the same reason.
gpg encryptedfile
Yes, I tired of passive-aggressive “useless use of cat” blogposts too. Another reason: you are testing a pipeline and will eventually run “some-program inputfile”, but whilst testing you just want to catenate the file rather than process it. You start with cat somefile | …, and then ^cat^some-program when done (bash example)
I recently had an init script fail on me because of the ‘while …. done < input' trick. It seems busybox/ash didn't support it. On the other hand, 'cat file | while … done' worked fine.
I find the “while … done < inputfile" thing spectacularly unreadable, especially if the while is more than a few lines of code.
So while I tend to grind my teeth when seeing pipelines that use cat, several greps and a few seds when a single sed would do a better job (which it pretty much always would) I'll let the "cat inputfile | while …" thing pass for reasons of readability alone — generally the single extra fork is going to be totally swamped by whatever is going on in the loop anyway.
cat “$@” | …
But almost everything else is laziness or otherwise unnecessary, as twerner showed.
You always want a function for long loops and similar things:
process_input() { while … done }
process_input < inputfile
Tell your shell then to protect you from accidental use of ‘>’ (noclobber with zsh)
OK, maybe gpg was a bad example, but the general idea stands.
@Philip Hands – I think that “< inputfile executable" works, but a quick test with "< inputfile while read line ; do echo $line ; done" makes me think it doesn't work. Not sure how readable it would be anyway.