Wednesday, April 1, 2009

find & grep command to search string (Cygwin version)

There are few limitations with Windows search, e.g.
-You cannot preview the search results.
-The regular expression in Windows is not unified with other regular expression formats. The Windows search for phase or word do not recognize the syntax like


Then, let's use grep to do the work. If you do not have cygwin, install it!
Now, I want to search for the places in .h files where it contains the text "typedef" at the start of the line and may follow with some other strings but must have "_mbstate_t".

$find ../ -iname \*.h -exec grep -B 3 -i "^typedef\(.*\)_mbstate_t" '{}' \; -print

Basically, find command needs the path and the file name you need to search.
Here, I tell the find to search the one directory upward for any files which have .h" or .H at the end of files. -iname option is for case-insensitive.
Remarkably, in Cygwin, you need to have the escape for * like \*.h but you don't need to do this on native *nix. The examples shown here are only tested under Cygwin.

Next, -exec option is to follow with a command where it takes the arguments from find and execute it. We want to grep any lines starting with "typedef" (^typedef) and follow with some string (.*) and _mbstate_t in any files which passed from find command.
"^typedef\(.*\)_mbstate_t" is normal regular expression for this job.
^typedef is to have typedef at the start of the line.
\(.*\)_mbstate_t is to match _mbstate_t which contains any strings or spaces before the search string. The backslash is the escape character to group (.*)
(For more information about regular expression, google regular expression)
-i is for case-insensitive.
-B 3 is to display 3 lines before the matching line.

If we want to search for both .cpp and .h files, we can group the search within (..) as well.

$find ../ \( -iname \*.h -o -iname \*.cpp \)

However, if you often need to repeat this search, you may put it into the shell script instead.

# File: - Simplify find & grep for source & header file
if [ $# -lt 2 ]
echo ""
echo "Usage: $0 [-i] search_path search_what"
echo "-i for non case-sensitive, default is case-sensitive"
exit 0

case "$1" in
find $1 \( -name \*.cpp -o -name \*.h \) -exec grep -i $2 "{}" \; -print
find $1 \( -name \*.cpp -o -name \*.h \) -exec grep $2 "{}" \; -print

exit 0

Beyond the example here, in my opinion find command is one of the most often used commands, therefore please don't forget to have a quick look at the find man page.

See also:

"The process of preparing programs for a digital computer is especially attractive, not only because it can be economically and scientifically rewarding, but also because it can be an aesthetic experience much like composing poetry or music." Donald E. Knuth