
Questão 1
Eu posso usar
grep -o '^[[:alpha:]_]\+[[:blank:]]*([[:blank:]]*)' /etc/rc.d/init.d/functions
para obter saída como abaixo:
systemctl_redirect ()
checkpid()
__kill_pids_term_kill_checkpids()
__kill_pids_term_kill()
__pids_var_run()
__pids_pidof()
daemon()
killproc()
pidfileofproc()
pidofproc()
status()
echo_success()
echo_failure()
echo_passed()
echo_warning()
update_boot_stage()
success()
failure()
passed()
warning()
action()
strstr()
is_ignored_file()
is_true()
is_false()
apply_sysctl()
E também quero saber quantas ocorrências foram correspondidas, então uso -c
a opção, desta vez só consigo 26
, posso combinar conteúdos e contagens correspondentes comgrep
construídas emopções? Se não, como fazer?
Questão 2
Encontrei uma solução no Github para responder à pergunta 1:
grep -o '^[[:alpha:]_]\+[[:blank:]]*([[:blank:]]*)' /etc/rc.d/init.d/functions \
| tee >(echo -e "\n`wc -l` matched.")
Mas a saída costuma ser estranha, o que ocorre após um novoprompt de shell!Por que?
Responder1
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
GNUismos \+
):
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, \w
está limitado a letras ASCII, adicione a -Mopen=locale
para incluir qualquer letra em qualquer escrita alfabética de acordo com a localidade, como nas abordagens grep
ou awk
(algumas awk
))
Sobre sua pergunta 2, é porque bash
(ao contrário de zsh
) não espera comandos iniciados na substituição de processos causando esse tipo de problema. VerA saída de substituição do processo está fora de ordempara mais detalhes.
Responder2
Em vez de tee
usar uma ferramenta comopee
:
grep -o '^[[:alpha:]_]\+[[:blank:]]*([[:blank:]]*)' /etc/rc.d/init.d/functions |
pee cat 'sleep 1; echo -e "\n`wc -l` matched."'
Se pee
não estiver disponível, isso pode ser feito com um bash
shell separado e silenciar seus prompts com unset
e shopt
:
bash -c \
"unset PS0 PS1 PS2 PS3
shopt -u promptvars
grep -o '^[[:alpha:]_]\+[[:blank:]]*([[:blank:]]*)' \
/etc/rc.d/init.d/functions |
tee >( sleep 1s; printf '\n%s matched.' `wc -l`; )
sleep 2s"
Respostas gerais:
Não pode ser feito com uma única instância do
grep
.Para obter uma contagem completa quando há mais de uma correspondência por linha com
grep -o
, usewc -l
:printf "foo bar baz\nbuz biz\n" | grep -o 'b[^ ]*' | wc -l
Saída:
4
Se uma contagem prefixada for necessária, use
nl
, (oucat -n
):printf "foo bar baz\nbuz biz\n" | grep -o 'b[^ ]*' | nl
Saída:
1 bar 2 baz 3 buz 4 biz
Com processos paralelos,ou seja
tee >(echo -e "\n`wc -l` matched.")
não há garantia de qual processo termina primeiro. Às vezes, um pequeno atraso pode ser adicionado para garantir o pedido.
Imprimir paralelo "foo" primeiro, então "ah" após um atraso de 1 segundo:
echo foo | tee >(sleep 1s; rev)
Imprimir paralelo "ah" primeiro, então "foo" após um atraso de 1 segundo:
echo foo | tee >(rev) >(sleep 1s;cat) > /dev/null