Você sempre pode fazer:
grep -o ... | awk '{print};END{if (NR) print "\n" NR " matched."}'
Ou faça tudo em awk (o que também evitaria os -o e \+ GNUisms):
awk 'match($0, /^[[:alpha:]_]+[[:blank:]]*\([[:blank:]]*\)/) {
print substr($0, RSTART, RLENGTH)
n++
}
END{if (n) print "\n" n " matched.")'
ou perl :
perl -lne 'for (/^\w+\h*\(\h*\)/g) {print; $n++}
END {print "\n$n matched." if $n}'
(observe que, nesse caso, o \w está limitado a letras ASCII, adicione -Mopen=locale para incluir qualquer letra em qualquer script alfabético de acordo com a localidade, como em grep ou awk (alguns awk ) abordagens)
Sobre sua pergunta 2, isso porque bash (ao contrário de zsh ) não espera por comandos iniciados na substituição do processo causando esse tipo de problema. Consulte A saída de substituição do processo está fora da ordem para obter mais detalhes.