A saída 'grep' pode corresponder ao conteúdo e conta? Se não, como?

0

Questão 1

Eu posso usar

grep -o '^[[:alpha:]_]\+[[:blank:]]*([[:blank:]]*)' /etc/rc.d/init.d/functions

para obter resultados 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 eu também quero saber quantas ocorrências foram correspondidas, então eu uso a opção -c , desta vez eu só recebo 26 , posso combinar conteúdo combinado e contagens com grep opções integradas ? Se não, como?

Questão 2

Eu 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 é produzido após um novo prompt de shell ! Por quê?

    
por liyang 21.11.2017 / 09:42

2 respostas

3

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.

    
por 21.11.2017 / 11:59
0

Em vez de tee , use uma ferramenta como pee :

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 shell bash 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:

  1. Não pode ser feito com uma única instância de grep .

    Para obter uma contagem completa quando houver mais de uma correspondência por linha com grep -o , use wc -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 , (ou cat -n ):

    printf "foo bar baz\nbuz biz\n" | grep -o 'b[^ ]*' | nl
    

    Saída:

         1  bar
         2  baz
         3  buz
         4  biz
    
  2. Com processos paralelos, i.e.

    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 paralelamente " foo " primeiro, depois " oof " após um atraso de 1 segundo:

    echo foo | tee >(sleep 1s; rev)
    

    Imprimir paralelamente " oof " primeiro, depois " foo " após um atraso de 1 segundo:

    echo foo | tee >(rev) >(sleep 1s;cat) > /dev/null
    
por 21.11.2017 / 09:54

Tags