Como dobrar 'grep -c token * .h * .cpp' em uma única contagem?

0

Estou adicionando autotestes ao código C ++, o que garante que não haja NDEBUG e Posix declarar dependências (a história do verso abaixo). O primeiro teste procura a inclusão de <assert.h> e <cassert> :

FAILED=0
COUNT=$($EGREP -c '(assert.h|cassert)' *.h *.cpp)
if [[ "$COUNT" -ne "0" ]]; then
    FAILED=1
    echo "Found Posix assert headers" | tee -a "$TEST_RESULTS"
fi

Produzindo:

************************************
Testing: No Posix assert

./cryptest.sh: line 1130: [[: 3way: value too great for base (error token is "3way")
...

Quando eu depurar, vejo:

bash -x ./cryptest.sh
...

++ egrep -c '(assert.h|cassert)' 3way.h adler32.h aes.h ...
+ COUNT='3way.h:0
adler32.h:0
aes.h:0
...

Assim, cada arquivo recebe sua própria linha e conta.

A página grep man indica o seguinte. Não discute a saída de várias linhas.

-c, --count
    Only a count of selected lines is written to standard output.

O comportamento parece ter algo a ver com Controle de saída (da página man) e -l, --files-with-matches . Eu também tentei a opção -L, --files-without-match . Isso produz um erro semelhante.

Minha pergunta é: como posso grep dobrar os resultados em uma contagem?

Ou talvez eu deva perguntar: grep e egrep são a ferramenta certa para o trabalho? Se grep e egrep não são a ferramenta certa, então o que devo usar?

Este é um script de shell Bash que é executado em todas as plataformas suportadas. Cada plataforma inclui BSDs, Linux, OS X, Solaris e Unix (e todas as variantes móveis, como Android e iOS). Temos que trabalhar para conseguir o que precisamos em termos de ferramentas como grep e egrep :

GREP=grep
EGREP=egrep
SED=sed
AWK=awk
DISASS=objdump
DISASSARGS=("--disassemble")
...

# Fixup
if [[ "$IS_SOLARIS" -ne "0" ]]; then
    IS_X64=$(isainfo 2>/dev/null | "$GREP" -i -c "amd64")
    if [[ "$IS_X64" -ne "0" ]]; then
        IS_X86=0
    fi

    # Need something more powerful than the non-Posix versions
    if [[ (-e "/usr/gnu/bin/grep") ]]; then
        GREP=/usr/gnu/bin/grep;
    fi
    if [[ (-e "/usr/gnu/bin/egrep") ]]; then
        EGREP=/usr/gnu/bin/egrep;
    fi
    if [[ (-e "/usr/gnu/bin/sed") ]]; then
        SED=/usr/gnu/bin/sed;
    fi
    if [[ (-e "/usr/gnu/bin/awk") ]]; then
        AWK=/usr/gnu/bin/awk;
    else
        AWK=nawk;
    fi

    DISASS=dis
    DISASSARGS=()
fi

...

História anterior

Nosso projeto recentemente realizou CVE-2016-7420 devido a usuários que criaram o projeto com outras ferramentas, como Autotools e CMake. O CVE é um resultado direto da omissão de -DNDEBUG para versões de release / produção. As outras ferramentas não configuram a maneira como fazemos, e também não informamos aos usuários (1) que não podem usar outras ferramentas de compilação ou (2) usuários devem definir -DNDEBUG para lançamento / produção.

Nossas correções estão sendo muito mais profundas do que "simplesmente defina NDEBUG para release / production" na documentação. Estamos destruindo todas as dependências em NDEBUG e Posix assert para que as pessoas não possam entrar acidentalmente na configuração. Também estamos exigindo que os usuários solicitem uma configuração de depuração definindo DEBUG ou _DEBUG ; caso contrário, eles obtêm a configuração de lançamento.

Enquanto um assert e o SIGART que se segue são geralmente irritantes em compilações de lançamento, considerados benignos na compilação de depuração e tomados como garantidos, observamos:

  • Somos uma biblioteca de segurança (lidamos com informações confidenciais)
  • Uma falha na declaração de informações confidenciais dos egressos para o sistema de arquivos (arquivos principais e relatórios de falhas)
  • Uma falha na afirmação de informações confidenciais de egressos para fornecedores de plataformas como Apple (CrashReporter), Apport (Ubuntu), Microsoft (Relatório de Erros do Windows)
  • Empresas como Apple, Google e Microsoft cooperam com o governo para explorar as informações confidenciais
por jww 17.09.2016 / 19:23

2 respostas

3

Observação: o seguinte é baseado na implementação GNU de grep , mas eu acho que deve ser aplicado no seu caso também

Como observado no manual do GNU grep (ênfase minha)

grep searches the named input FILEs for lines containing a match to the
given PATTERN.  If no files are specified, or if the file “-” is given,
grep  searches  standard  input.   By default, grep prints the matching
lines.

Além disso,

-c, --count
       Suppress  normal output; instead print a count of matching lines
       **for each input file**.  With the -v,  --invert-match  option  (see
       below), count non-matching lines.

(e o comportamento padrão é prefixar tal saída com o nome do arquivo - embora isso possa ser suprimido usando a opção -h ).

Ao concatenar seus arquivos de destino em um único fluxo de entrada e canalizar isso para grep , você deve ser capaz de substituir esses dois comportamentos e obter uma única contagem sem prefixo:

COUNT=$(cat *.h *.cpp | $EGREP -c '(assert.h|cassert)')

IMHO isso se qualificaria como um uso útil do gato; provavelmente o que você foi desaconselhado é Uso inútil do gato

    
por 17.09.2016 / 20:23
1

resposta da steeldriver (do cat files | grep -c <token> ) foi meu primeiro pensamento quando li o título da sua pergunta. Mas vejo que, no seu trecho de script, você não está usando a contagem, além de compará-lo a zero - ou seja, você está perguntando "quantos estão aí?" quando você quer saber "há algum?" Considere usar -q :

if "$EGREP" -q -- 'assert\.h|cassert' *.h *.cpp
then
    FAILED=1
    echo "Found Posix assert headers" …
fi

Notas:

  • Você deve sempre citar suas referências de variáveis de shell (por exemplo, "$EGREP" ) a menos que você tenha um bom motivo para não e você tem certeza de que sabe o que está fazendo. Se você definiu EGREP=grep -e , isso seria um motivo razoavelmente bom para dizer $EGREP sem aspas, mas veja esta resposta para Implicações da segurança de esquecer de citar uma variável em shells bash / POSIX .
  • -q (ou, equivalentemente, --quiet ou --silent ) significa “Silencioso; não escreva nada na saída padrão. Saia imediatamente com status zero se alguma correspondência for encontrada mesmo que um erro tenha sido detectado. ” Isto não só lhe dá o comportamento funcional que você quer (isto é, o mesmo comportamento funcional da resposta da steeldriver), mas com o benefício de desempenho que grep sairá assim que encontrar uma correspondência e não precisar ler todos os arquivos.
  • É aconselhável colocar -- entre as opções de um comando e seus argumentos para impedir que um nome de arquivo comece com - de ser interpretado como uma string de opção.
  • Você não precisa colocar parênteses em toda a expressão regular.
  • grep 'assert.h' corresponderá a assert h , assert,h , assert3h , assertph , etc. Se você não se importa, isso é com você. Se você quiser corresponder apenas assert.h , grep para assert\.h .
por 23.09.2016 / 03:15