Searching: grep, find and Wildcards

intermediate
14 min

Searching: grep, find and Wildcards

A Linux system holds hundreds of thousands of files. The professionals who seem to "just know" where everything is are really fluent with three search tools: shell wildcards for matching filenames, find for locating files by any property, and grep for searching inside files. Master these and no log line or config setting can hide from you.

Shell Wildcards (Globbing)

Before a command runs, the shell expands wildcard patterns into matching filenames:

  • * – any sequence of characters (including none)
  • ? – exactly one character
  • [abc] – one character from the set; [0-9] for a range
bash
ls *.md # all Markdown files here ls report-??.txt # report-01.txt, report-42.txt ... ls img_[0-9]*.png # img_1.png, img_20240101.png ... cp src/*.js backup/ # wildcards work with any command

Note that * does not match hidden files (those starting with a dot), and an unmatched pattern is passed through literally on most shells. Always preview a destructive wildcard with ls before giving it to rm.

find: Locate Files by Name, Type, Size, Age

find walks a directory tree and tests every entry against your criteria: find WHERE CONDITIONS.

bash
find . -name "*.log" # by name, in the current tree find /etc -name "*.conf" # search a specific tree find . -iname "readme*" # case-insensitive name find . -type d -name node_modules # directories only (-type f = files) find /var/log -size +10M # bigger than 10 MB find . -mtime -7 # modified within the last 7 days

Quote the pattern ("*.log") so the shell hands it to find instead of expanding it first.

Acting on What find Finds

find can execute a command on every match, which turns it into a bulk-operations engine:

bash
find . -name "*.tmp" -delete # delete matches find . -type f -name "*.sh" -exec chmod u+x {} \; # make scripts executable find . -name "*.log" -exec grep -l "ERROR" {} \; # combine with grep

{} is replaced by each filename and \; ends the command. Test with a harmless action like -print before using -delete.

grep: Search Inside Files

grep prints every line matching a pattern—the tool you will use most in this lesson:

bash
grep "ERROR" app.log # lines containing ERROR grep -i "error" app.log # case-insensitive grep -n "TODO" main.py # show line numbers grep -r "database_url" ~/project # recursive through a directory grep -rn --include="*.js" "apiKey" . # only in .js files, with line numbers grep -v "DEBUG" app.log # invert: lines NOT containing DEBUG grep -c "GET" access.log # count matching lines grep -A2 -B2 "panic" app.log # 2 lines of context after/before

A Taste of Regular Expressions

grep patterns are regular expressions, a mini-language for describing text:

bash
grep "^root" /etc/passwd # ^ anchors to line start grep "sh$" /etc/passwd # $ anchors to line end grep -E "40[34]" access.log # 403 or 404 grep -E "error|warn" app.log # either word (-E enables extended syntax)

Even these four patterns—start, end, character set, alternation—cover most daily needs.

find vs grep: Which One?

  • Looking for a file (by name, size, date)? Use find.
  • Looking for text inside files? Use grep -r.
  • Both at once? Let find select files and grep search them, as shown above.

Practice Session

bash
find /etc -name "*.conf" 2>/dev/null | head grep -n "PATH" ~/.bashrc grep -rc "root" /etc/passwd /etc/group ls /etc/*.d 2>/dev/null | head

The 2>/dev/null hides permission-denied noise—a preview of redirection, coming next lesson.

Key Takeaways

  • Wildcards (*, ?, [...]) match filenames and work with every command.
  • find locates files by name, type, size or age, and can act on matches with -exec or -delete.
  • grep -rn searches text recursively with line numbers; -i, -v, -c, -A/-B refine results.
  • Anchors ^ and $ plus alternation | give you 80% of regex power.

Next lesson: Pipes, Redirection and Command Chaining — connect these tools into pipelines.