Let's assume we have the following files and directories:
-rw-rw-r--. a.c
-rw-rw-r--. a.cpp
-rw-rw-r--. a.h
-rw-rw-r--. a.html
drwxrwxr-x. dir.c
drwxrwxr-x. dir.cpp
drwxrwxr-x. dir.h
I want to execute grep on all the files (it should also look in subdirectories) which meet the following conditions:
.h
, .c
and .cpp
.On files found, execute grep and print the file name where grep finds something.
But this ends up in a very long command with a lot of repetitions like:
find . -name '*.c' -type f -exec grep hallo {} \; -print -o -name '*.cpp' -type f -exec grep hallo {} \; -print -o -name '*.h' -type f -exec grep hallo {} \; -print
Can the conditions be grouped to remove the repetitions or are there any other possible simplifications?
My system is Fedora 33, with GNU grep, GNU find and bash available.
With Bash's extglob
and globstar
special options:
shopt +s extglob globstar
grep -s regex **/*.+(cpp|c|h)
You can put the first line in ~/.bashrc
so you don't need to manually enable them options in every shell.
If you happened to have directories with those extensions, Grep would complain without the -s
flag.
In GNU Find, use the -regex
option to make it easier:
find . -type f -regex '.*\.\(c\|h\|cpp\)' -exec grep regex {} +
find . -type f -regextype awk -regex '.*\.(c|h|cpp)' -exec grep regex {} +
With POSIX tools only:
find . -type f \( -name '*.[ch]' -o -name '*.cpp' \) -exec grep regex {} +