じゃ、こんなのは?

find . \( -name '*.c' -o -name '*.cc' -o -name '*.cpp' \) -exec basename {} \; | \
( c=0 ; cc=0 ; cpp=0 ; while read i; do case $i in *.c ) c=`expr $c + 1`;; *.cc) cc=`expr $cc + 1`;; *.cpp) cpp=`expr $cpp + 1`;; esac; done; printf '*.c = %d\n*.cc = %d\n*.cpp = %d\n' $c $cc $cpp )

長すぎたので途中で折り返してる。
てか1行で書く必要は無いのか?