# How I use grep without fighting the flags

A beginner-friendly guide to building grep commands for searching text, using recursion, context lines, includes, excludes, and safer regex choices.

- Date: 2026-09-27
- URL: https://ilham.dev/posts/how-to-use-grep-without-fighting-regex/
- Markdown: https://ilham.dev/posts/how-to-use-grep-without-fighting-regex/index.md
- Tags: linux, grep, regex, tools
- Reading time: 4 min


`grep` is the command I use when I know some text exists somewhere, but I do not
remember which file contains it.

The basic idea is simple:

```sh
grep "database" app.log
```

Plain meaning:

> Look for the word `database` inside `app.log`.

The hard part is not the basic search. The hard part is remembering which flags to
use when the search gets bigger. That is where the
[grep Pattern Builder](/tools/grep-pattern-builder/) helps.

## Step 1: start with plain text

If you are new to `grep`, start with the simplest possible command:

```sh
grep "error" app.log
```

This searches one file.

I use quotes even for simple words because it becomes a habit that also works for
phrases:

```sh
grep "connection refused" app.log
```

Without quotes, the shell splits the phrase into separate arguments.

## Step 2: search without caring about uppercase

Logs are not always consistent. You may see `Error`, `ERROR`, or `error`.

Use `-i` for case-insensitive search:

```sh
grep -i "error" app.log
```

Plain meaning:

> Match `error` regardless of uppercase or lowercase.

This is one of the flags I use most often.

## Step 3: show line numbers

Use `-n` to show line numbers:

```sh
grep -n "connection refused" app.log
```

This is useful when you need to open the file and jump to the exact line later.

## Step 4: search a whole directory

Use `-r` for recursive search:

```sh
grep -r "DATABASE_URL" .
```

Plain meaning:

> Search this directory and its subdirectories.

For code, I often combine it with `-n`:

```sh
grep -rn "DATABASE_URL" .
```

Now I get both file paths and line numbers.

## Step 5: include only certain files

If a project has many files, search only the type you care about:

```sh
grep -rn --include="*.js" "fetch(" .
```

Plain meaning:

> Search recursively, show line numbers, but only inside `.js` files.

You can use this for logs too:

```sh
grep -rn --include="*.log" "timeout" /var/log/my-app
```

## Step 6: exclude noisy folders

Some folders are usually not useful to search:

- `node_modules`;
- `.git`;
- `vendor`;
- `dist`;
- `build`.

Example:

```sh
grep -rn --exclude-dir=node_modules --exclude-dir=.git "apiKey" .
```

This keeps the result readable and makes the search faster.

## Step 7: show context around a match

Sometimes the matching line is not enough. Use context flags.

Show 3 lines after each match:

```sh
grep -n -A 3 "Exception" app.log
```

Show 3 lines before each match:

```sh
grep -n -B 3 "Exception" app.log
```

Show 3 lines before and after:

```sh
grep -n -C 3 "Exception" app.log
```

I use `-C` a lot for logs because the useful information is often around the error,
not only on the error line.

## Step 8: choose fixed string when regex is not needed

By default, `grep` treats the pattern like a regular expression. That can surprise
you when searching for characters like `.`, `[`, `]`, `?`, or `*`.

If you want to search for exact text, use `-F`:

```sh
grep -F "user.name" config.txt
```

Plain meaning:

> Search for the literal text `user.name`, not a regex where `.` means any
> character.

When I am not intentionally using regex, `-F` is safer.

## Step 9: invert the match

Use `-v` to show lines that do not match:

```sh
grep -v "healthcheck" access.log
```

Plain meaning:

> Show every line except healthcheck lines.

This is useful for removing noise from logs.

You can combine it:

```sh
grep -v "healthcheck" access.log | grep -i "error"
```

That means:

> Remove healthcheck lines, then search the remaining lines for errors.

## Step 10: count matches

Use `-c` to count matching lines:

```sh
grep -c "500" access.log
```

This does not count every occurrence. It counts matching lines. That is usually fine
for quick log checks.

## A practical example

Suppose I need to find where a project uses `JWT_SECRET`, but I do not want to search
`node_modules`.

I can build:

```sh
grep -rn --exclude-dir=node_modules --exclude-dir=.git "JWT_SECRET" .
```

If I want exact text, not regex:

```sh
grep -rnF --exclude-dir=node_modules --exclude-dir=.git "JWT_SECRET" .
```

That is the kind of command the [grep Pattern Builder](/tools/grep-pattern-builder/)
helps assemble without forgetting flags.

## My grep checklist

When building a grep command, I ask:

1. Am I searching one file or a directory?
2. Do I need recursive search with `-r`?
3. Do I need line numbers with `-n`?
4. Should uppercase/lowercase be ignored with `-i`?
5. Is this exact text? If yes, use `-F`.
6. Should I include only certain file types?
7. Should I exclude noisy folders?
8. Do I need context lines with `-A`, `-B`, or `-C`?
9. Do I want matching lines or non-matching lines with `-v`?

`grep` is not just a regex tool. It is a way to ask a very focused question across
files. The builder helps turn that question into a command I can read before I run.
