Globbing and Regex: So Similar, So Different

Grepping is awesome, as long as you don't glob it up! This article covers some grep and regex basics.

There are generally two types of coffee drinkers. The first type buys a can of pre-ground beans and uses the included scoop to make their automatic drip coffee in the morning. The second type picks single-origin beans from various parts of the world, accepts only beans that have been roasted within the past week and grinds those beans with a conical burr grinder moments before brewing in any number of complicated methods. Text searching is a bit like that.

For most things on the command line, people think of *.* or *.txt and are happy to use file globbing to select the files they want. When it comes to grepping a log file, however, you need to get a little fancier. The confusing part is when the syntax of globbing and regex overlap. Thankfully, it's not hard to figure out when to use which construct.

Globbing

The command shell uses globbing for filename completion. If you type something like ls *.txt, you'll get a list of all the files that end in .txt in the current directory. If you do ls R*.txt, you'll get all the files that start with capital R and have the .txt extension. The asterisk is a wild card that lets you quickly filter which files you mean.

You also can use a question mark in globbing if you want to specify a single character. So, typing ls read??.txt will list readme.txt, but not read.txt. That's different from ls read*.txt, which will match both readme.txt and read.txt, because the asterisk means "zero or more characters" in the file glob.

Here's the easy way to remember if you're using globbing (which is very simple) vs. regular expressions: globbing is done to filenames by the shell, and regex is used for searching text. The only frustrating exception to this is that sometimes the shell is too smart and conveniently does globbing when you don't want it to—for example:


grep file* README.TXT

In most cases, this will search the file README.TXT looking for the regular expression file*, which is what you normally want. But if there happens to be a file in the current folder that matches the file* glob (let's say filename.txt), the shell will assume you meant to pass that to grep, and so grep actually will see:


grep filename.txt README.TXT

Gee, thank you so much Mr. Shell, but that's not what I wanted to do. For that reason, I recommend always using quotation marks when using grep. 99% of the time you won't get an accidental glob match, but that 1% can be infuriating. So when using grep, this is much safer:


grep "file*" README.TXT

Because even if there is a filename.txt, the shell won't substitute it automatically.