Searching and Finding Things: grep and find
Learn to search inside files for text with grep and find files across the system with find.
Two different questions
Searching on the command line means one of two things, and each has its own tool.
- "Which lines contain the word
timeout?" The tool is grep. It searches the text inside files. - "Where is the file called
config.yml?" The tool is find. It searches for files and folders by name and other properties.
grep: search inside files
The basic form is grep pattern file. grep prints every line of the file that contains the pattern.
grep "error" server.log
grep -i "error" server.log
grep -n "error" server.log
grep -c "error" server.log
grep -v "debug" server.log
grep -r "TODO" ~/projects
grep -rl "password" /etc 2>/dev/null
- The first command prints each line containing
error. -iignores upper and lower case.-nshows the line number in front of each match.-cprints only how many lines matched.-vinverts the match: it prints lines that do not contain the word.-rsearches recursively through every file in a folder.-lprints only the names of files that contain a match.2>/dev/nullhides error messages such as "Permission denied" (explained in the redirection lesson).
Another useful option is -w, which matches whole words only. Options can be combined, for example grep -rin "todo" ..
grep in a pipe
grep can read the output of another command instead of a file. Without a file name it reads from its input.
ps aux | grep nginx
history | grep git
dmesg | grep -i usb
This lets you filter the output of any command. ps aux lists running programs, history lists commands you ran earlier and dmesg prints system messages.
Patterns: a first look at regular expressions
The pattern does not have to be a fixed word. A regular expression is a pattern language for text. A few symbols are enough to start:
^matches the start of a line.$matches the end of a line..matches any single character.*matches zero or more of the previous character.[abc]matches one character from the list.
grep "^Error" log.txt
grep "done$" log.txt
grep "gr.y" words.txt
grep -E "cat|dog" pets.txt
grep -E "[0-9]{3}-[0-9]{4}" contacts.txt
^Errormatches lines that start withError.done$matches lines that end withdone.gr.ymatchesgrayandgrey.-Eturns on extended expressions.cat|dogmatches either word.[0-9]{3}-[0-9]{4}matches three digits, a dash, then four digits.
You do not need to master these now. Knowing they exist is enough.
find: search for files
The form is find where tests. The first argument is the place to start looking. Everything after it narrows down the match.
find . -name "notes.txt"
find /home -name "*.jpg"
find . -iname "readme*"
find . -type d -name "node_modules"
.means the current folder and everything inside it.-namematches the file name. Put patterns with*in quotes sofindsees the wildcard instead of the shell.-inameignores case.-type dkeeps only directories.-type fkeeps only regular files.
More tests: size, time and owner
find . -type f -size +100M
find . -mtime -7
find . -mtime +30
find . -user alex
-size +100Mmatches files larger than 100 megabytes. A minus sign means smaller.-mtime -7matches files modified less than 7 days ago.-mtime +30means more than 30 days ago.-user alexmatches files owned byalex.
You can add several tests. They all have to match.
Doing something with the results
find . -name "*.tmp" -delete
find . -name "*.log" -exec wc -l {} \;
find . -name "*.txt" | xargs grep -l "invoice"
-deleteremoves every match.-exec command {} \;runs a command once for each match.{}stands for the current file name.xargstakes lines from a pipe and puts them on the end of another command, so this last line searches inside each.txtfile thatfindfound.
find without -delete first. Check the list, then add -delete. A safe cleanup is: run find . -name "*.tmp", check that the list looks right, then run it again with -delete.Quick alternatives
locate notes.txt
which python3
type ls
locatesearches a prebuilt index, so it is instant. The index is updated withsudo updatedb, so very new files can be missing.which python3shows the path of a command.type lsshows whether a name is a program, a built-in command or an alias.