Search only certain file types
Search only certain file types with grep -r --include='*.sh'. When --exclude comes first, files that match neither option are searched as well.
A recursive search should look at shell scripts only, and adding an exclusion makes text files appear in the results.
mkdir -p proj/sub
echo 'TODO shell' > proj/a.sh
echo 'TODO text' > proj/b.txt
echo 'TODO deep' > proj/sub/c.sh
cd proj
grep -r --include='*.sh' TODO .
echo ---
grep -r --exclude='c*' --include='*.sh' TODO ../sub/c.sh:TODO deep
./a.sh:TODO shell
---
./b.txt:TODO text
./sub/c.sh:TODO deep
./a.sh:TODO shell--include takes a glob that grep matches against each base name while it walks the tree, so the first command finds both scripts and skips b.txt. The GNU grep manual gives the rule for mixing the two options: the last one that matches a file wins, and a file that matches none is searched unless the first such option was --include. In the second command the first option is --exclude, so b.txt is searched, and c.sh is searched too because the later include overrides the exclusion.
The glob is matched against the base name, never a path with a slash in it. Quote it, so the shell leaves it for grep. Put every --include first when the intent is to search only those files. Directories are not filtered by these options, which is what --exclude-dir is for.