The old school notation (usable with archaic things like Bourne Shell, and not so archaic things such as Korn shell) is:
for f in `find . ! -type d`
do
line=`grep -i 'todo' $f | sed 's/^[ \t]*//'`
if [ -n "$line" ]
then
echo "$f:"
echo "$line"
fi
done
You could speed up the overall processing, though, by using:
find . ! -type d -print0 | xargs -0 grep -i 'todo' /dev/null |
perl -p -e '($name) = split /:/;
if ($saved ne $name) { $saved = $name; print "$name:\n"; }
s/^$name:\s*//;'
The find
is modified to handle spaces in names; the xargs
also handles spaces in names, and runs the grep
command on /dev/null plus some files - which ensures that matching lines are preceded by the file name. The perl
script splits the line at the first colon - so file names containing colons are not good news. It compares that name with what it had saved before; if they are different, then it prints out the new name, colon and newline to give you the file heading. Then it removes the file name and trailing spaces before (automatically) printing the line. (Don't use '-w' with Perl; it complains about $saved being uninitialized. If you must (it is good practice), add BEGIN { $saved = ""; }
.)
This is likely to perform better than the shell loop because it invokes grep just a few times rather than once per file, and doesn't invoke the sed
at all (instead of once per file).