Reputation: 65
Goal: is to print the name of every .c program in a directory specified by first argument that contains some word.
My idea was:
word = "word"
for file in specifiedDirectory with c file extension
do
if grep -w $word $file ; then
echo $file
fi
done
Upvotes: 2
Views: 167
Reputation: 80931
With a modern find the following should do what you want.
wordfind() {
find "$1" -name '*.c' -exec grep -wl word {} \+
}
You could also spit all the files out and use xargs
to try to cut down the number of times grep
needs to be run.
Something like this.
wordfind() {
find "$1" -name '*.c' -print0 | xargs -0 -r grep -wl word
}
Use "$@"
in place of "$1"
in either of the above functions to support passing multiple directories to the functions instead of just one directory. (Also adds support for supplying arbitrary arguments to find but that's a different topic entirely.)
Upvotes: 1
Reputation: 11593
If you have GNU grep
you can also just do
grep -rwl --include '*.c' word specifiedDirectory
With relevant options from man page
-r, --recursive
Read all files under each directory, recursively, following symbolic links only if they are on the command line.
This is equivalent to the -d recurse option.
-w, --word-regexp
Select only those lines containing matches that form whole words. The test is that the matching substring must
either be at the beginning of the line, or preceded by a non-word constituent character. Similarly, it must be
either at the end of the line or followed by a non-word constituent character. Word-constituent characters are
letters, digits, and the underscore.
-l, --files-with-matches
Suppress normal output; instead print the name of each input file from which output would normally have been
printed. The scanning will stop on the first match. (-l is specified by POSIX.)
--include=GLOB
Search only files whose base name matches GLOB (using wildcard matching as described under --exclude).
Upvotes: 3
Reputation: 113864
shopt -s globstar
word="word"
for file in path/to/**/*.c
do
grep -l -w "$word" "$file"
done
Notes:
To avoid unpleasant surprises, always put shell variables, like word
or file
in double-quotes as shown above. Tnis prevents word-splitting.
With the -l
option, grep
will print the name of any matching file. This makes the if
and echo
statements unnecessary.
In order to search a whole directory tree, we use bash's globstar
feature. This enables **/
to match zero or more directories. (On Mac OSX, this feature is not available unless you have upgraded to bash
version 4.0 or better.)
In bash
assignment statements, there can be no spaces on either side of the equal sign. Let's consider how bash
looks at the line:
word = "word"
As bash
interprets that line, it will try to execute the command word
with two arguments: =
and word
. If that is not what you want, the spaces must be removed.
grep
will accept multiple filenames on its command line. So, there is no need for the for
loop:
shopt -s globstar
word="word"
grep -l -w "$word" path/to/**/*.c
Suppose we want to run the script as ./word someDirectory
and have it search the someDirectory
tree for the c
files. In the script that the first argument can be referenced as $1
. So, create a file named goto
which its execute bit set (chmod +x word
) with the contents:
#!/bin/bash
shopt -s globstar
word="word"
for file in "$1"/**/*.c
do
grep -l -w "$word" "$file"
done
Likewise for the simplified version:
#!/bin/bash
shopt -s globstar
word="word"
grep -l -w "$word" "$1"/**/*.c
Upvotes: 1