1499

I'm working on a script to grep certain directories:

{ grep -r -i CP_Image ~/path1/; grep -r -i CP_Image ~/path2/; grep -r -i CP_Image ~/path3/; grep -r -i CP_Image ~/path4/; grep -r -i CP_Image ~/path5/; } | mailx -s GREP [email protected] 

How can I limit results only to extensions .h and .cpp?

6
  • 15
    Tried grep -r -i CP_Image ~/path1/*.{h,cpp}? Commented Sep 20, 2012 at 16:31
  • 11
    Use The Silver Searcher: ag -i CP_Image ~/path[1-5] | mailx -s GREP [email protected]. Job done. Commented Oct 9, 2013 at 17:25
  • possible duplicate of grep --exclude/--include syntax (do not grep through certain files) Commented Oct 9, 2013 at 17:48
  • 14
    The GNU guys really messed up when they added -r to grep to have it search for files as that breaks the UNIX mantra of having tools that "do one thing and do it well". There's a perfectly good tool for finding files with a VERY obvious name. Commented Oct 9, 2013 at 17:58
  • 1
    @Dogweather , egrep has been deprecated for a long time. From grep's man page: Direct invocation as either egrep or fgrep is deprecated, but is provided to allow historical applications that rely on them to run unmodified. To achieve the same result, one must use grep -E Commented Apr 18, 2018 at 11:03

12 Answers 12

2008

Just use the --include parameter, like this:

grep -inr --include \*.h --include \*.cpp CP_Image ~/path[12345] | mailx -s GREP [email protected] 

That should do what you want.

To take the explanation from HoldOffHunger's answer below:

  • grep: command

  • -r: recursively

  • -i: ignore-case

  • -n: each output line is preceded by its relative line number in the file

  • --include \*.cpp: all *.cpp: C++ files (escape with \ just in case you have a directory with asterisks in the filenames)

  • ./: Start at current directory.

Sign up to request clarification or add additional context in comments.

7 Comments

@Hong where is the documentation that -R is for symbolic links?
Can someone explain why this syntax works as opposed to what's described in the man page --include=GLOB
This example seems to have a high score because it covers such a wide range of possibilites but the answer given below of grep -r --include=*.txt 'searchterm' ./ really explains the essence of the answer
why not use double quotes instead of backslash? e.g: grep -r -i --include="*.h" --include="*.cpp" CP_Image
This example DOES NOT WORK!
|
479

Some of these answers seemed too syntax-heavy, or they produced issues on my Debian Server. This worked perfectly for me:

grep -r --include=\*.txt 'searchterm' ./ 

...or case-insensitive version...

grep -r -i --include=\*.txt 'searchterm' ./ 
  • grep: command

  • -r: recursively

  • -i: ignore-case

  • --include: all *.txt: text files (escape with \ just in case you have a directory with asterisks in the filenames)

  • 'searchterm': What to search

  • ./: Start at current directory.

Source: PHP Revolution: How to Grep files in Linux, but only certain file extensions?

6 Comments

You should escape the * using \*.cpp or '*.cpp'. Otherwise it won’t give the expected result when the working directory contains some *.txt files.
@Melebius can you explain why it needs escaping - does it have anything to do with the CPP or TXT extensions you mentioned? Or did you just use those as examples?
@SimonEast These extensions are those used in this question and answer, nothing special otherwise. It would probably work without escaping when using --include=<pattern> but it is important to escape * with --include <pattern> (a space instead of =) which feels very similar otherwise.
Did not answer the question! Jasmine asked for two file types in a single search!
This example DOES NOT WORK!
|
99
grep -rnw "some thing to grep" --include=*.{module,inc,php,js,css,html,htm} ./ 

9 Comments

grep -rn "some thing to grep" --include=*.{module,inc,c,h} *
Nice answer. Cleaner than the accepted on IMO but you should add search criteria as @ashish noted
why is --include option after needle, not with other options?
@vladkras, what do you mean needle? Is it --?
Almost, but that didn't work for me--it kept trying to match on --include=*.foo. The working solution was wrapping the --include value in quotes. E.g. --include="*.foo".
|
65

Use:

find . -name '*.h' -o -name '*.cpp' -exec grep "CP_Image" {} \; -print 

4 Comments

i'd suggest grouping those -name arguments. strange things can happen if you don't. find . \( -name '*.h' -o -name '*.cpp' \) -exec grep "CP_Image" {} \; -print
use with additional "-type f" to ignore all directory objects, only interested in files.
I used this method for years and it works but it's a LOT slower than recursive grep since find's exec spawns a separate grep process for each file to be searched.
Addressing @beaudet's comment, find can optionally bundle arguments, reducing invocations of the called process to a minimum. find . \( -name \*.h -o -name \*.cpp \) -exec grep -H CP_Image {} + This is suggested but not highlighted in @fedorqui's answer below and is a worthwhile improvement. The -H argument to grep here is useful when find only identifies a single matching file. This could eliminate the usage of -print in the answer. If your total list of files is sufficiently small, using a recursive shell glob (eg. {path1,path2}/**/*.{cpp,h}) might be preferable.
37

There isn't any -r option on HP and Sun servers, but this way worked for me on my HP server:

find . -name "*.c" | xargs grep -i "my great text" 

-i is for case insensitive search of string.

7 Comments

I've come across several servers for web hosting companies that do not have the --include option available for fgrep and this is the command line that I use in those instances.
The --include option is also not available when using Git for Windows (MinGW/MSys).
@DarrenLewis available in Git Bash for Windows. But strangely, it adds colorful aliases like ll but does not add --color=auto to grep.
This should be the accepted answer for completeness, portability, and brevity!
Re "HP and Sun servers": Do you mean for HP-UX and Solaris?
|
31

Nelson's answer is good:

grep -r -i --include \*.h --include \*.cpp CP_Image ~/path[12345] | mailx -s GREP [email protected] 

But it can be simplified to:

grep -r -i --include=\*.{h,cpp} CP_Image ~/path[12345] | mailx -s GREP [email protected] 

6 Comments

What does "The below answer" refer to? References to relative positions of answers are not reliable as they depend on the view (votes/oldest/active) and changing of the accepted answer and change over time (for votes, active, and accepted state). Please respond by editing your answer, not here in comments (without "Edit:", "Update:", or similar - the answer should appear as if it was written today).
Can we simply use grep command along with ls command?
@Harsha Sure. use pipe to make the output of ls as the input of grep. such as ls | grep *.h
Could you provide me a link that would give explanations as to how I can fully understand this?
|
15

Since this is a matter of finding files, let's use find!

Using GNU find you can use the -regex option to find those files in the tree of directories whose extension is either .h or .cpp:

find -type f -regex ".*\.\(h\|cpp\)" # ^^^^^^^^^^^^^^^^^^^^^^^ 

Then, it is just a matter of executing grep on each of its results:

find -type f -regex ".*\.\(h\|cpp\)" -exec grep "your pattern" {} + 

If you don't have this distribution of find you have to use an approach like Amir Afghani's, using -o to concatenate options (the name is either ending with .h or with .cpp):

find -type f \( -name '*.h' -o -name '*.cpp' \) -exec grep "your pattern" {} + # ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 

And if you really want to use grep, follow the syntax indicated to --include:

grep "your pattern" -r --include=*.{cpp,h} # ^^^^^^^^^^^^^^^^^^^ 

1 Comment

I needed a script which returned exit status 1 if the grep command matched any files. I started out using find+xargs+grep. But the fact that xargs returns exit status 123 if grep returns 1 made things more complicated. It was more straightforward to just use grep in my case.
11

The easiest way is:

find . -type f -name '*.extension' 2>/dev/null | xargs grep -i string 

Add 2>/dev/null to kill the error output.

To include more file extensions and grep for password throughout the system:

find / -type f \( -name '*.conf' -o -name "*.log" -o -name "*.bak" \) 2>/dev/null | xargs grep -i password 

Comments

5

ag (the silver searcher) has pretty simple syntax for this

 -G --file-search-regex PATTERN Only search files whose names match PATTERN. 

so

ag -G *.h -G *.cpp CP_Image <path> 

1 Comment

using ag 2.2.0, i needed to put my flags last: ag _string_to_find_ -G _filename_regex_
2

You should write "-exec grep " for each "-o -name ":

find . -name '*.h' -exec grep -Hn "CP_Image" {} \; -o -name '*.cpp' -exec grep -Hn "CP_Image" {} \; 

Or group them by ( )

find . \( -name '*.h' -o -name '*.cpp' \) -exec grep -Hn "CP_Image" {} \; 

Option '-Hn' shows the file name and line.

Comments

1

Here is a method I normally use to find .c and .h files:

tree -if | grep \\.[ch]\\b | xargs -n 1 grep -H "#include" 

Or if you need the line number as well:

tree -if | grep \\.[ch]\\b | xargs -n 1 grep -nH "#include" 

Comments

0

If you want to filter out extensions from the output of another command e.g. "git":

files=$(git diff --name-only --diff-filter=d origin/master... | grep -E '\.cpp$|\.h$') for file in $files; do echo "$file" done 

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.