4 Usage
Here is an example command that invokes GNU grep:
grep -i 'hello.*world' menu.h main.c
This lists all lines in the files menu.h and main.c that
contain the string ‘hello’ followed by the string ‘world’;
this is because ‘.*’ matches zero or more characters within a line.
See Regular Expressions.
The -i option causes grep
to ignore case, causing it to match the line ‘Hello, world!’, which
it would not otherwise match.
Here is a more complex example,
showing the location and contents of any line
containing ‘f’ and ending in ‘.c’,
within all files in the current directory whose names
start with non-‘.’, contain ‘g’, and end in ‘.h’.
The -n option outputs line numbers, the -- argument
treats any later arguments as file names not options even if
*g*.h expands to a file name that starts with ‘-’,
and the empty file /dev/null causes file names to be output
even if only one file name happens to be of the form ‘*g*.h’.
grep -n -- 'f.*\.c$' *g*.h /dev/null
Note that the regular expression syntax used in the pattern differs from the globbing syntax that the shell uses to match file names.
See Invoking grep, for more details about
how to invoke grep.
Here are some common questions and answers about grep usage.
- How can I list just the names of matching files?
grep -l 'main' test-*.c
lists names of ‘test-*.c’ files in the current directory whose contents mention ‘main’.
- How do I search directories recursively?
grep -r 'hello' /home/gigi
searches for ‘hello’ in all files under the /home/gigi directory. For more control over which files are searched, use
findandgrep. For example, the following command searches only C files:find /home/gigi -name '*.c' ! -type d \ -exec grep -H 'hello' '{}' +This differs from the command:
grep -H 'hello' /home/gigi/*.c
which merely looks for ‘hello’ in non-hidden C files in /home/gigi whose names end in ‘.c’. The
findcommand line above is more similar to the command:grep -r --include='*.c' 'hello' /home/gigi
- What if a pattern or file has a leading ‘-’?
For example:
grep "$pattern" *
can behave unexpectedly if the value of ‘pattern’ begins with ‘-’, or if the ‘*’ expands to a file name with leading ‘-’. To avoid the problem, you can use -e for patterns and leading ‘./’ for files:
grep -e "$pattern" ./*
searches for all lines matching the pattern in all the working directory’s files whose names do not begin with ‘.’. Without the -e,
grepmight treat the pattern as an option if it begins with ‘-’. Without the ‘./’, there might be similar problems with file names beginning with ‘-’.Alternatively, you can use ‘--’ before the pattern and file names:
grep -- "$pattern" *
This also fixes the problem, except that if there is a file named ‘-’,
grepmisinterprets the ‘-’ as standard input. - Suppose I want to search for a whole word, not a part of a word?
grep -w 'hello' test*.log
searches only for instances of ‘hello’ that are entire words; it does not match ‘Othello’. For more control, use ‘\<’ and ‘\>’ to match the start and end of words. For example:
grep 'hello\>' test*.log
searches only for words ending in ‘hello’, so it matches the word ‘Othello’.
- How do I output context around the matching lines?
grep -C 2 'hello' test*.log
prints two lines of context around each matching line.
- How do I force
grepto print the name of the file?Append /dev/null:
grep 'eli' /etc/passwd /dev/null
gets you:
/etc/passwd:eli:x:2098:1000:Eli Smith:/home/eli:/bin/bash
Alternatively, use -H, which is a GNU extension:
grep -H 'eli' /etc/passwd
- Why do people use strange regular expressions on
psoutput?ps -ef | grep '[c]ron'
If the pattern had been written without the square brackets, it would have matched not only the
psoutput line forcron, but also thepsoutput line forgrep. Note that on some platforms,pslimits the output to the width of the screen;grepdoes not have any limit on the length of a line except the available memory. - Why does
grepreport “binary file matches”?If
greplisted all matching “lines” from a binary file, it would probably generate output that is not useful, and it might even muck up your display. So GNUgrepsuppresses output from files that appear to be binary files. To force GNUgrepto output lines even from files that appear to be binary, use the -a or ‘--binary-files=text’ option. To eliminate the “Binary file matches” messages, use the -I or ‘--binary-files=without-match’ option. - Why doesn’t ‘grep -lv’ print non-matching file names?
‘grep -lv’ lists the names of all files containing one or more lines that do not match. To list the names of all files that contain no matching lines, use the -L or --files-without-match option.
- I can do “OR” with ‘|’, but what about “AND”?
grep 'paul' /etc/motd | grep 'franc,ois'
finds all lines that contain both ‘paul’ and ‘franc,ois’.
- Why does the empty pattern match every input line?
The
grepcommand searches for lines that contain strings that match a pattern. Every line contains the empty string, so an empty pattern causesgrepto find a match on each line. It is not the only such pattern: ‘^’, ‘$’, and many other patterns causegrepto match every line.To match empty lines, use the pattern ‘^$’. To match blank lines, use the pattern ‘^[[:blank:]]*$’. To match no lines at all, use an extended regular expression like ‘a^’ or ‘$a’. To match every line, a portable script should use a pattern like ‘^’ instead of the empty pattern, as POSIX does not specify the behavior of the empty pattern.
- How can I search in both standard input and in files?
Use the special file name ‘-’:
cat /etc/passwd | grep 'alain' - /etc/motd
- Why can’t I combine the shell’s ‘set -e’ with
grep?The
grepcommand follows the convention of programs likecmpanddiffwhere an exit status of 1 is not an error. The shell command ‘set -e’ causes the shell to exit if any subcommand exits with nonzero status, and this will cause the shell to exit merely becausegrepselected no lines, which is ordinarily not what you want.There is a related problem with Bash’s
set -e -o pipefail. Sincegrepdoes not always read all its input, a command outputting to a pipe read bygrepcan fail whengrepexits before reading all its input, and the command’s failure can cause Bash to exit. - Why is this back-reference failing?
echo 'ba' | grep -E '(a)\1|b\1'
This outputs an error message, because the second ‘\1’ has nothing to refer back to, meaning it will never match anything.
- How can I match across lines?
Standard grep cannot do this, as it is fundamentally line-based. Therefore, merely using the
[:space:]character class does not match newlines in the way you might expect.With the GNU
grepoption -z (--null-data), each input and output “line” is null-terminated; see Other Options. Thus, you can match newlines in the input, but typically if there is a match the entire input is output, so this usage is often combined with output-suppressing options like -q, e.g.:printf 'foo\nbar\n' | grep -z -q 'foo[[:space:]]\+bar'
If this does not suffice, you can transform the input before giving it to
grep, or turn toawk,sed,perl, or many other utilities that are designed to operate across lines. - What do
grep, -E, and -F stand for?The name
grepcomes from the way line editing was done on Unix. For example,eduses the following syntax to print a list of matching lines on the screen:global/regular expression/print g/re/p
The -E option stands for Extended
grep. The -F option stands for Fixedgrep; - What happened to
egrepandfgrep?7th Edition Unix had commands
egrepandfgrepthat were the counterparts of the modern ‘grep -E’ and ‘grep -F’. Although breaking upgrepinto three programs was perhaps useful on the small computers of the 1970s,egrepandfgrepwere deemed obsolescent by POSIX in 1992, removed from POSIX in 2001, deprecated by GNU Grep 2.5.3 in 2007, and changed to issue obsolescence warnings by GNU Grep 3.8 in 2022; eventually, they are planned to be removed entirely.If you prefer the old names, you can use your own substitutes, such as a shell script named
egrepwith the following contents:#!/bin/sh exec grep -E "$@"