If you use your Fedora system for more than just browsing the web, you have probably needed to search for text in your files. For instance, you might be a developer that can’t remember where you left some code snippet. Or you might be looking for a setting stored in your system configuration files. Whatever the reason, there are plenty of ways to search for text on your Fedora system. This article will show you how, including using the built-in utility grep.
The grep utility allows you to search for text, or more specifically text patterns, on your file system. The name grep comes from global regular expression print. Yikes, what a mouthful! This is because a regular expression (or regex) is a way of defining text patterns.
The grep utility lets you find and print out matches on these patterns — thus the name. It’s a powerful system, and you can even find it in modern code editors like Visual Studio Code or Atom.
Harnessing all the power of regular expressions is a topic bigger than this article, for sure. The simplest kind of regex can be just a word, or a portion of a word. That pattern is simply “the following characters, in the same order.” The pattern is searched line by line. For example:
- pciutil – matches any time the 7 characters pciutil appear together — including pciutil, pciutils, pciutil123, and foopciutil.
- ^pciutil – matches any time the 7 characters pciutil appear together immediately at the beginning of a line (that’s what the ^ stands for)
- pciutil$ – matches any time the 7 characters pciutil appear together immediately before the end of a line (that’s what the $ stands for)
More complicated expressions are also possible. Special characters are used in a regex as wildcards, or to change the way the regex works. If you want to match on one of these characters, use a \ (backslash) before the character.
For instance, the . (period or full stop) is a wildcard that matches any single character. If you use it in the expression pci.til, it matches pciutil, pci4til, or pci!til, but does not match pcitil. There must be a character to match the . in the regular expression.
The ? is a marker in a regex that marks the previous element as optional. So if you built on the previous example, the expression pci.?til would also match on pcitil because there need not be a character between i and t for a valid match.
The + and * are markers that stand for repetition. While + stands for one or more of the previous element, * stands for zero or more. So the regex pci.+til would match any of these: pciutil, pci4til, pci!til, pciuuuuuutil, pci423til. However, it wouldn’t match pcitil — but the regex pci.*til would.
Examples of grep
Now that you know a little about regex, let’s put it to work. Imagine that you’re trying to find a configuration file that mentions a user account jpublic. You tried a bunch of files already, but none were the correct one, and you’re sure it’s there. So, try searching the /etc folder (using sudo because some subfolders are not readable outside the root account):
$ sudo grep -r jpublic /etc/
The -r switch searches the folder recursively. The utility prints a list of matching files, and the line where the hit occurred. In most modern terminal environments, the hit is color highlighted for better readability.
Imagine you have a much larger selection of files in /home/shared and you need to establish which ones mention the name MacNulty. However, you’re not sure whether the capitalization will be consistent, and you’re just looking for names of files, not the context. Also, you believe someone may have misspelled the name as McNulty in some places.
Use the -l switch to only output filenames with a match, a ? marker for optional a in the name, and -i to make the search case-insensitive:
$ sudo grep -irl 'ma\?cnulty' /home/shared
This command will match on strings like Macnulty, McNulty, Mcnulty, and macNulty with no problem. You’ll get a simple list of filenames where the match was found in the contents.
These are only the simplest ways to use grep and regular expressions. You can learn a lot more about both using the info grep command.
But wait, there’s more…
The grep command is venerable but in some situations may not be as efficient as newer search utilities. For instance, the ripgrep utility is engineered to be a fast search utility that can take the place of grep. We covered ripgrep as part of an article on Rust and Rust applications previously in the Magazine:
It’s important to note that ripgrep has its own command line switches and syntax. For example, it has simple switches to print only filename matches, invert searches, and many other useful functions. It can also ignore based on .rgignore files placed in any subdirectories. (It’s also noteworthy that the -r switch is used differently for ripgrep, because it is automatically recursive.)
To install, use this command:
$ sudo dnf install ripgrep
To explore the options, use the manual page (man rg). You’ll find that many, but not all, options are the same as grep.
Have fun searching!
It’s a little confusing that \ is originally said to “escape” the meaning of a metacharacter, but later is used to do the exact opposite “\?” in the ‘ma\?cnulty’ example. gnu grep uses “basic regular expressions” by default, where ? is not a metacharacter and \ is actually used to enable its regular expression meaning.
I find it more useful to just use egrep (or grep -E) to enable extended regular expressions, which better match what I generally expect from regular expressions.
Depends what your greping for though, as you could be searching for ?, +, (, ), et al., in that case, a bre would be more compact/readable.
It always confused me what regular expressions i am able to do with grep and for what i require egrip (grep -E).
Good article and reminder what grep can do.
you also have the options -A and -B
to grep n lines after the match
grep -An string /path/of/files
grep -A2 -E “^root” /etc/passwd
to grep n lines before
grep -B n string /path/of/file
grep -B2 -E “^shut” /etc/passwd
to color the results
to found files with match
grep -rl string /directory/to/search/
grep -rl root /etc/