15

Sometimes I come across superfluous uses of cat, e.g.:

$ cat file | grep pattern

instead of:

$ grep pattern file

or:

$ cat file | somecommand options

instead of:

$ somecommand options < file

or:

$ <file somecommand options

I tend to directly edit those cases and remove the useless uses of cat.

What do you think, is that a best practice for the Unix & Linux stackexchange, or should other actions (e.g. adding a comment) be preferred?

On what is useless

The above examples and link are about useless-uses-of-cat - why useless? Basically because an unnecessary call of cat is made, i.e. a fork() and a /exec() system call are wasted. It is useless because concatenating just one thing results in that one thing (input = output, the indentity function).

Note that the context still matters. For a class of useless-uses-of cat the concatenation of one file is a necessity but not sufficient.

Useful examples:

  • a command line where cat foo | is used as an example to provide a non-seekable input is a useful use of cat
  • a command line where cat is used to output a proprietary source (e.g. MVS datasets on ceratin IBM systems)
  • a command like ( cmd1; cat midpart; cmd2; cat bottom; ) > completeoutput

Usually, it should not be difficult to spot useless-uses-of-cat because of the context.

  • 1
    FYI - in IBM Unix System Services, you can't grep <pattern> <file> if your <file> is an MVS dataset. You have to use cat "//'MVS.DATASET'" | grep <pattern> if you want to grep a dataset. – transistor1 Jun 6 '13 at 0:43
  • i prefer the hand of god, lot of people come here (to stack pages), copy, paste and edit. without your change they would use the cat, maybe change the file and params. – tgkprog Jun 10 '13 at 18:37

10 Answers 10

31

If you don't mind a dissenting opinion from a junior member here, I'd like to say: please don't.

Although it may be useless on its own, cat somefile is a nice stand-in for dosomething --write-to stdout. So, to take a simple case, let's pretend someone asks the question, "How do I only show the non-blank lines in myfile.conf?" The answer grep -v ^$ < myfile.conf might be more pleasing to read than cat myfile.conf | grep -v ^$, but it's not as helpful to the person with the similar question, "How do I only show the non-blank lines in the output from my application?" The UUOC answer, though, let's them just copy the | grep -v ^$ part and paste it onto their command line after the command invocation, see that it works, give you an upvote, and close their browser and get back to work.

Of course this becomes a lot more useful when you start doing something more complex, such as chaining commands together. In a script, as I'm debugging it and trying to understand how each command affects the stream, I might start out with:

foo --bar > file1.txt
cat file1.txt | sort -r > file2.txt
cat file2.txt | uniq -c

and now I can examine the intermediate files, and, once I'm convinced that the right thing is happening each time, put everything together easily with just copy-and-paste or removing the excess junk:

foo --bar | sort -r | uniq -c

Hardly the most interesting example, of course. But being able to just replace cat somefile with something-interesting is a simple thing to do when you're still trying to understand how the stuff after your UUOC is going to behave.

Stack Exchange sites are here to (among other things) help people learn, and being a little more verbose helps accomplish that.

  • Upvoted because you have argued your point well. I would still contend that looking at the edits provides the utility you champion. – jasonwryan May 28 '13 at 21:58
  • 3
    Rather than breaking up the stream you can insert tee commands where you want a copy of the output: foo --bar | tee file1.txt | sort -r | tee file2.txt | uniq -c – l0b0 Jun 6 '13 at 11:44
  • 1
    The prefix form < file2.txt sort -r > file2.txt etc. should be as convenient for your copy'n'paste working style, right? – maxschlepzig Jun 10 '13 at 14:00
15

There are many more important peeves. Useless uses of cat are harmless and are often clearer. Reserve your wrath for things that actually matter, such as unquoted variable expansions in shell snippets.

If I see a suggested edit that solely removes useless uses of cats, I'll reject it as too minor. Perhaps even as invalid if I'm in a rejecting mood.

If you're changing a multi-step pipeline, at least edit cat somefile | command1 | command2 to <somefile command1 | command2, which keeps the source at the beginning, and not the mid-endian command1 <somefile | command2. As many readers aren't aware that you can put the redirection before the command, <somefile command1 is surprising to some readers, which is an argument for writing cat somefile | command1 (though I do prefer to start with <somefile1 myself).

If you really want to edit out useless complications, edit out the useless uses of dd.

  • 2
    I've no problem to edit - say - unquoted variable expansions and useless uses of dd and useless uses of cat. Some arguments for useless cat are too general for my taste, I mean, in the same way you could argue that useless uses of dd/unquoted variable expansions are easier to read, easier to copy and paste, more known to the general public, one thing less to remember ... – maxschlepzig May 31 '13 at 14:12
  • @maxschlepzig cat is very easy to understand and has a low risk of misuse. dd has a unique syntax and is vulnerable to typos (if and of are but one key away on most keyboards). Unquoted variable expansions are wrong unless there is an assurance that the value doesn't contain spaces or globbing characters. – Gilles May 31 '13 at 14:16
10

As the site is a wiki and subsequent edits are transparent, rather than just commenting I think people should edit the offending answers (or questions) and save a feline.

This has the benefit of ensuring that, as a learning resource, the site maintains unimpeachable standards and—strictly as a by-product, continues to be a welcome habitat for the pedant and cognoscente.

In addition to preserving our whiskered friends, edits are also called for in cases where other egregious offenses against Unix propriety are committed, for example:

5

I have not edited that particular code pattern, but if I do change code, I tend to:

  1. only do so in questions
  2. make sure there are no comments or answers (yet)
  3. write a comment to the OP to verify if (s)he agrees to the change and invite to roll-back if not.

With answers, I would only leave a comment. There is a much greater chance that the poster of the answer will improve the post. If they do not the answer probably will get less (or neg) votes anyway.

If there are answers or comments, then there is good chance someone already took the errors into account in there, and an edit could invalidate that.

I recommend to be careful with these kind of things and make the OP more explicitly aware of what you did per comments than just rely on the system. I have e.g. seen a post on this site where such a minor thing as adding a tag caused misinterpretation of an (ambiguous) question. OP was not notified per comment of the inappropriate disambiguation by the edit, did not react to that edit (arguable OP's fault, but with 5-6 edits OP might have lost track even when notified by the system of the edits), resulting in a question closed appropriately as duplicate if tags would have been correct, but not based on content.

5

There is one issue that hasn’t been mentioned yet as far as I see, and that I personally learned the hard way:

The two lines

cat somefile | someprog

and

someprog <somefile

are not completely equivalent! In the second line, standard input to someprog is seekable, whereas in the first case, it is not.

So if there is a question, say, “cat xxx | foobar fails with some-complex-error-message” and you change it into “<xxx foobar fails with some-complex-error-message”, it may no longer fail at all, causing lots of confusion.

  • On Unix, most of the time xxx < somefile can be written much better as xxx somefile... – vonbrand Jan 2 '16 at 22:33
4

I'd better add a link to these explanation, perhaps add a variant without "cat" or give a hint about this possibility, but also leave the original code.

Perhaps, it was there for a reason, say, uniformity.

Giving an explicit link to the explanation is more educating for all the readers.

3

Promote proper programming. Stamp out silly code smell memes. Educate the masses. Edit away, I say!

2

I think the "superfluous" uses should be left alone. I frequently cat into pipelines and the reason is that I don't have to remember whether the target command is going to produce different output, as some do when you give them a file or multiple filenames on the command line. cat bar | grep foo is the same as grep foo bar, but cat bar blatz | grep foo isn't the same as grep foo bar blatz. If I consistently use cat, then that's one less thing to remember in a congeries of fiddly things to remember under Unix.

  • But the talk is about redirection (<) vs "cat", not cmdline arguments. – imz -- Ivan Zakharyaschev May 30 '13 at 14:29
  • Also the talk is about editing such code, not whether is a good or bad habit to use it. – manatwork May 31 '13 at 6:21
  • @mana Editing away such uses is an explicit judgment that the uses are bad, else why bother? – Kyle Jones May 31 '13 at 7:06
  • 5
    @imz Language is full of redundancies; the "unnecessary" parts make it easier for fallible human beings to use. Editing those parts away is often the exact opposite of being helpful. – Kyle Jones May 31 '13 at 7:06
2

The "useless use of cat" idea is just an excuse for pedants to harass other programmers making a perfectly reasonable technical and stylistic programming decision. Don't make the edits.

0

As mentioned in another answer, the catless variant isn't always equivalent. Sometimes cat is even more secure. If you're using grep to examine a log, then you have three basic choices:

  1. grep 'pattern' /path/to/log
  2. grep 'pattern' < /path/to/log
  3. cat /path/to/log | grep "pattern"

For most things, you wouldn't notice a difference here, except in the number of key strokes you need. Now, what happens when log has can only be read by root? I wanted to take a look at failed logins over the ssh so that I could show a few of my coworkers why that machine doesn't allow for password-based logins, and so I try to use variant #1 and get this:

grep: /var/log/auth.log: Permission denied

Nothing surprising there. Now, I could sudo chmod +r, but there's probably a good reason why that log has its permissions set that way by default and it's not the best practice to go changing permissions without thinking about it first. So my next option is to use sudo for examining the log. If I use sudo grep 'pattern' /path/to/log, then grep is now running as root. grep is a fairly complicated piece of code, and there are so many ways to screw up the handling of regular expressions. Now if sudo cat /var/log/auth.log | grep 'pattern', then only cat, a much simpler program, is running as root. I suppose I could also do this with input redirection, but I can never remember how to do it with sudo. The cat way has another advantage: when I get the permission error, it's pretty easy to press the up error, Ctrl+a and type sudo. Easy peasy.

Now imagine, we have a relative newbie, just getting the hang of using grep, awk and the rest of the family, but still not 100% on the finer details of good practice. He knows that sudo makes him a god for a single command and that he shouldn't use it too lightly, but he also knows that there are a lot of little tasks where he still has to sudo up, e.g. all the package managers on the most popular distros. So he's gotten into the habit of automatically sudoing up whenever some vaguely system-administration related task gives him a permission error. So,one day he comes across the recommendation to check his /var/log/auth.log for brute force attacks. He tries grep as a normal user, but gets the permission error and immediately tries it again with sudo. If he's using variant #1, then he just ran grep (or perhaps an even more complicated piece of code) as root. If he goes with the cat variant, then only cat gets promoted to root. And let's not even consider the idea of issuing blanket advice to just sudo chmod +r in such cases! Next thing you know, he'll be adding +w to system configuration files.

Long story short: leaving the cat in doesn't hurt; the performance penalty is trivial, especially on modern hardware; it occasionally makes things more secure; it potentially makes a line more readable (left to right in the direction of the pipe flow, fewer positional arguments, ability to change out intervening elements easily even when they take their arguments in a different order). Leave the cat in and stop spawning useless mental processes thinking about it -- your mind is far worse at fork()ing than your computer!

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .