4
\$\begingroup\$

I have to read a lot of code and search through many code bases. I frequently find myself using something like grep -r --include=.C "test string" . to find files containing a certain string or regular expression. However, to simplify this and expedite the process, I want to create a function that allows me to specify what I am looking for, what are acceptable file extensions and what are inacceptable file extensions.

The function I have written is below. I am not sure if this follows best practices. Also, the hack using the brace expansion with the .\? is bad. I really appreciate any feedback that you have.

findInFile() {
 # Function to be placed in bash profile
 # Allows user to specify what contents of a file they are looking for
 # in what file types and in what NOT file types
 # Iterate over the number of scripts arugments
 # TODO: How can I create documentation for this function outside of code comments?
 while [[ "$#" -gt 0 ]]
 do
 case 1ドル in
 -ft|--fileTypes)
 local fileTypes=2ドル
 ;;
 -et|--excludeTypes)
 local excludeTypes=2ドル
 ;;
 *) # Catch the case where user does not specify 
 # these arguments
 local searchTerm=1ドル
 ;;
 esac
 shift
 done
 echo "fileTypes: $fileTypes"
 echo "excludeTypes: $excludeTypes"
 echo "searchTerm: $searchTerm"
 # TODO: Should probably clean up with case statement
 # TODO: I am using this \? in the include and exclude as a hack
 # to catch the case where only one file type is provided. 
 if [ -n "$fileTypes" ] && [ -n "$excludeTypes" ]
 then
 #searchString="grep -r --include=\*{$fileTypes} --exclude=\*{$excludeTypes} "$searchTerm" ."
 searchString="grep -r --include=\*{$fileTypes,.\?} --exclude=\*{$excludeTypes,.\?} "$searchTerm" ."
 elif [ -n "$fileTypes" ]
 then
 #searchString="grep -r --include=\*{$fileTypes} "$searchTerm" ."
 searchString="grep -r --include=\*{$fileTypes,.\?} "$searchTerm" ."
 elif [ -n "$excludeTypes" ]
 then
 #searchString="grep -r --exclude=\*{$excludeTypes} "$searchTerm" ."
 searchString="grep -r --exclude=\*{$excludeTypes,.\?} "$searchTerm" ."
 else
 searchString="grep -r "$searchTerm" ."
 fi
 #searchString="grep -r --include=\*{$fileTypes} "$searchTerm" ."
 echo "searchString: $searchString"
 eval $searchString
 # TODO: Allow the user to type a number to then programmatically jump to that
 # file in the text editor of their choice
}
asked Jan 3, 2019 at 23:42
\$\endgroup\$
4
  • \$\begingroup\$ check out ack and its contemporaries, designed to solve your exact problem. grep -r --include=.C "test string" becomes ack --cc "test string" beyondgrep.com/feature-comparison beyondgrep.com/why-ack \$\endgroup\$ Commented Jan 4, 2019 at 1:10
  • 1
    \$\begingroup\$ You should have a look at ag, the silver searcher -- very fast, automatically recursive, PCRE regexes. \$\endgroup\$ Commented Jan 4, 2019 at 2:00
  • \$\begingroup\$ @glenn take a look at ripgrep 😀 \$\endgroup\$ Commented Jan 4, 2019 at 5:52
  • 1
    \$\begingroup\$ I feel silly. All of these look like awesome options. I have been writing grep for years! This has been really helpful. Thank you everyone. \$\endgroup\$ Commented Jan 4, 2019 at 15:14

1 Answer 1

3
\$\begingroup\$

You can use [[ .. ]] instead of [ .. ] to do tests. The former is a bash builtin and saves a fork.

You don't need to eval anything since you're just building a couple of optional switches to grep. Start with empty strings and populate variables or an array, and pass the result to an invocation of grep as variables. This also avoids enumerating every possible combination of arguments (already 4 combos with 2 options -- that approach quickly becomes unsustainable).

There's no need to absorb searchTerm. Just leave it in the arguments and pass all those to grep, which allows you to include grep switches too, like -i.

Use set +x to see what's going on.

Tying it all together:

findInFile() {
 :<<_comment_
 Function to be placed in bash profile
 Allows user to specify what contents of a file they are looking for
 in what file types and in what NOT file types
 Iterate over the number of scripts arugments
_comment_
 declare -a select
 while [[ "$#" -gt 0 ]]
 do
 if [[ 1ドル =~ ^(-ft|--fileTypes|-et|--excludeTypes)$ ]]
 then
 local type="2ドル"
 [[ "$type" == *,* ]] && type="{$type}"
 if [[ 1ドル == *-f* ]]
 then 
 select+=( "--include=*$type" )
 else
 select+=( "--exclude=*$type" )
 fi
 shift 2
 else
 break
 fi
 done
 set -x
 grep -r ${select[@]} "$@" .
 { set +x; } 2>/dev/null
}

You can include long comments as here-docs piped to the null operator :.

answered Jan 4, 2019 at 1:53
\$\endgroup\$

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.