grep -i 'pattern' file matches the pattern regardless of case. With -i, error, Error, ERROR, and eRRoR all match the same search. It is one of the most-used grep flags because log files, error messages, and code identifiers are rarely consistent about capitalization.
The flag is short for --ignore-case. It works in every regex mode (grep, grep -E, grep -F, grep -P) and combines cleanly with the other flags you reach for daily. The one thing it does not do reliably is fold case outside ASCII, which is the gotcha that catches people searching non-English text. That caveat gets its own section below.
Set your values
Set your OS, search path, and pattern. Every grep example below updates with your values.
The one-liner
grep -i ':pattern' app.logThat prints every line in app.log that contains :pattern in any mix of upper and lower case. Note the PowerShell line has no extra flag: Select-String is case-insensitive by default, the opposite of grep. To make Select-String case-sensitive you add -CaseSensitive.
The pattern is quoted with single quotes so the shell does not expand or interpret it. Quote your grep patterns always, even when they look like plain words today, because the next edit might add a * or a $.
Combining -i with the flags you already use
-i stacks with the rest of grep's flag set. The combinations below are the ones I type most often.
-i with -r: case-insensitive recursive search
The single most useful combination. Search an entire directory tree, ignoring case.
grep -rin ':pattern' :search_path-r is recursive, -i ignores case, -n prints line numbers. This is the everyday "find every mention of this thing anywhere in the project" search. Add -I (capital i, distinct from -i) to skip binary files, which both GNU and BSD grep support.
-i with -w: whole word, any case
-w constrains the match to whole words, so :pattern does not match a substring of a longer identifier. Combined with -i, you get a case-insensitive whole-word search.
grep -iw ':pattern' app.logWithout -w, searching for error also matches errored, terror, and error_handler. With -iw, only the standalone word error, Error, or ERROR matches. PowerShell has no -w flag, so the word boundaries go into the regex as \b. See grep whole word matching for the full word-boundary reference.
-i with -v: invert, ignoring case
-v inverts the match: it prints lines that do not match. With -i, the exclusion is case-insensitive too.
grep -iv ':pattern' app.logThis prints every line that has no :pattern in it, regardless of how it was capitalized. Useful for trimming a known-noisy string out of output: grep -iv 'debug' drops every line mentioning debug in any case.
-i with -c: count matches, ignoring case
-c prints a count of matching lines instead of the lines themselves.
grep -ic ':pattern' app.logOne subtlety: -c counts matching lines, not total matches. A line with :pattern mentioned three times counts once. To count every occurrence including repeats on a line, use grep -io ':pattern' app.log | wc -l, where -o prints each match on its own line.
Case-insensitive recursive search across a codebase
Putting the combination to work: find every case-insensitive mention of a string in a project, with line numbers, skipping node_modules and .git.
grep -rin --exclude-dir=node_modules --exclude-dir=.git ':pattern' :search_pathGNU grep has --exclude-dir; BSD grep on macOS does not, so the mac variant pipes find into xargs. If you live on macOS and want the GNU flags, brew install grep gives you GNU grep as ggrep. The grep cheat sheet covers the filename-filtering patterns in more depth.
The locale and UTF-8 caveat
This is the part most -i tutorials skip. -i reliably folds ASCII case only. For the 26 Latin letters A-Z, -i always treats upper and lower as equivalent. Outside ASCII, case folding depends on your locale.
The locale is set by environment variables, chiefly LC_ALL, LC_CTYPE, and LANG. Check it with:
localeIf your locale is C or POSIX (common on minimal containers and stripped-down servers), grep does no non-ASCII case folding at all. With LC_CTYPE=C, grep -i 'eacute' will not match an accented E-acute against a lowercase e-acute, because the C locale knows nothing about accented characters.
A UTF-8 locale such as en_US.UTF-8 enables Unicode-aware case folding for accented Latin characters, Greek, Cyrillic, and most scripts that have a case distinction. To force it for one command:
LC_ALL=en_US.UTF-8 grep -i 'pattern' file.txtTwo specific traps worth naming:
- The Turkish dotted-i. In a Turkish locale (
tr_TR.UTF-8), uppercaseIlowercases to a dotlessi, and lowercaseiuppercases to a dotted capital. Sogrep -i 'I'behaves differently undertr_TR.UTF-8than underen_US.UTF-8. If a script searches forINDEXand runs on a Turkish-locale host, the match forindexcan silently fail. This is the canonical case-folding bug. - The C locale on containers. Docker base images frequently ship with
LANGunset, which defaults to theClocale. Agrep -ithat worked on your dev machine can quietly stop folding non-ASCII case inside the container. If a pipeline depends on non-ASCII matching, setLANGexplicitly in the image.
For pure ASCII text, none of this matters and -i just works. The caveat only bites once your data has accented or non-Latin characters.
Per-pattern case control with PCRE (?i)
-i is all-or-nothing: it applies to the entire pattern. Sometimes you want part of a pattern case-insensitive and the rest case-sensitive. PCRE mode (grep -P, GNU only) supports the inline (?i) flag for exactly this.
The inline flag turns case-insensitivity on from that point in the pattern onward:
grep -P '(?i):pattern' app.logYou can also scope it to a group with (?i:...), which makes only that group case-insensitive and leaves the rest of the pattern case-sensitive. For example, a pattern that matches the word log in any case but requires the rest to be exact uses (?i:log) followed by the case-sensitive part. PowerShell's .NET regex engine understands (?i) and (?i:...) the same way, which is why the Windows variant above pairs -CaseSensitive with an inline (?i) to flip just the relevant span.
(?i) is the right tool when -i is too blunt. If you only ever need whole-pattern folding, plain -i is simpler and works in every mode.
macOS BSD grep vs GNU grep
-i itself is identical on both. The differences are in the flags you combine it with.
| Behavior | GNU grep | BSD grep (macOS default) |
|---|---|---|
-i (ignore case) | Supported | Supported, identical |
--ignore-case long form | Supported | Supported |
-P (PCRE, needed for (?i)) | Supported | Not supported |
(?i) inline flag | Works under -P | No -P, so unavailable |
--exclude-dir (for -ri searches) | Supported | Not supported |
| Non-ASCII case folding | Locale-dependent (UTF-8 locale) | Locale-dependent (UTF-8 locale) |
-w whole word | Supported | Supported |
The practical takeaway: grep -i, grep -ri, grep -iw, grep -iv, and grep -ic all work the same on macOS and Linux. Only the PCRE-dependent (?i) and the --exclude-dir convenience flag are GNU-only. For those, brew install grep and use ggrep.
Common mistakes
1. Assuming -i folds non-ASCII case. It only reliably folds ASCII A-Z. Accented characters, Greek, Cyrillic, and other scripts depend on a UTF-8 locale. On a C-locale host (many containers), non-ASCII -i does nothing. Check locale before trusting a non-English -i search.
2. Forgetting the locale on containers. A grep -i that works locally can stop folding non-ASCII case inside Docker, where LANG is often unset. Set LANG in the image if the pipeline needs it.
3. The Turkish-i surprise. Under tr_TR.UTF-8, I and i do not fold to each other the way they do in English locales. Scripts that search for uppercase identifiers can fail on Turkish-locale hosts. Force LC_ALL=C or LC_ALL=en_US.UTF-8 for ASCII identifier searches that must be deterministic.
4. Adding -i to a pattern that already spans both cases. A pattern like [Ee]rror already matches Error and error. Adding -i on top is redundant and, worse, it also makes any other letters in the pattern case-insensitive, which may not be what you intended. Pick one mechanism: either -i for the whole pattern, or an explicit character class, not both.
5. Confusing -i with -I. Lowercase -i ignores case. Uppercase -I skips binary files. They are unrelated. grep -rI skips binaries; grep -ri ignores case; grep -riI does both.
6. Expecting -c to count occurrences. -c counts matching lines. Three matches on one line count as one. Use grep -io 'pattern' | wc -l for a true occurrence count.
When NOT to use -i
-i is the wrong choice when case is meaningful data:
- Matching constants versus variables. In most languages,
MAX_RETRIESis a constant andmaxRetriesis a variable. A case-insensitive search collapses the two. When you specifically want theSCREAMING_SNAKE_CASEconstant, search case-sensitively so the lowercase variable does not pollute the results. - Distinguishing types from instances.
Userthe class anduserthe instance variable are different things. Refactoring the class name with a case-insensitive grep will sweep up every instance variable too. - Environment variables versus values.
PATHthe variable andpathin a comment are unrelated. A case-sensitive search keeps configuration audits accurate. - Acronyms and identifiers in code review. When you grep a codebase to find every definition of
APIorURL, case sensitivity is usually what you want, because the lowercase forms appear inside hundreds of unrelated identifiers.
The rule of thumb: use -i for human-written prose (logs, messages, documentation) where capitalization is inconsistent and meaningless. Drop -i for code identifiers, where capitalization is a deliberate signal.
See also
- grep Cheat Sheet: the full grep reference covering regex modes, recursive search, context lines, and BSD vs GNU differences
- grep whole word matching: the
-wflag in depth, including the word-boundary edge cases - grep recursive search:
-rand-R, filename filtering, and excluding directories - regex cheat sheet: the regex reference for the patterns you feed into
grep -Eandgrep -P - External: GNU grep manual, FreeBSD grep(1) man page.





