Eu tenho um programa que soma uma coluna em um arquivo:
awk -v col=2 '{sum+=$col}END{print sum}' input-file
No entanto, ele tem um problema: se você fornecer um arquivo que não possui dados numéricos (ou se um número estiver faltando), ele o interpretará como zero.
Eu quero que ele produza um erro se um dos campos não puder ser analisado como um número.
Aqui está um exemplo de entrada:
bob 1
dave 2
alice 3.5
foo bar
Eu quero que ele produza um erro porque 'bar' não é um número, em vez de ignorar o erro.
Uma maneira razoável de testar seria comparar o campo usando testes semelhantes a
strtod
, que é o método que o awk usa para converter strings em números:O acima difere de strtod, pois não considera INFINITY ou NAN como "números". O requisito de espaço à esquerda pode ser relaxado sob o comportamento de divisão de campo padrão do awk - o que significa que os campos nunca conteriam espaço à esquerda:
Um refinamento adicional, graças ao comentário e resposta de Stéphane aqui :
Dividido para uma legibilidade um pouco melhor, esse regex é:
... onde a intenção é permitir um possível + ou - à esquerda, então um número de ponto flutuante ou um número hexadecimal. O número de ponto flutuante tem dígitos iniciais opcionais, um separador de opção (aqui fixado para ser um ponto
.
), seguido por algum número de dígitos, opcionalmente seguido por um expoente. O número hexadecimal deve começar com0x
ou0X
, seguido por dígitos hexadecimais, um separador, mais dígitos hexadecimais e, opcionalmente, seguido por uma "potência" (expoente). Todo o segundo campo deve corresponder a um desses formatos (conforme ancorado por^
e$
). Omitidas aqui, para fins desta pergunta, estão as opções NAN e INFINITY.Outra opção seria forçar uma conversão numérica, depois compará-la com zero e depois comparar a entrada original com algo que converteria em zero; mais especificamente, ele começa com um + ou - opcional, então é seguido por zeros ou seguido por um ponto e zeros:
Acabei com isso:
Isso usa typeof, que é uma extensão GNU awk.
typeof($col)
retorna 'strnum' se$col
for um número válido e 'string' ou 'unassigned' se não for.Consulte Posso determinar o tipo de uma variável awk?
Cabe a você complicá-lo se quiser que ele também trate
.0
ou.0e+33
como representações válidas de0
; observe queawk
ignorará o lixo à direita ao converter strings em números ("1.4e1e3"+0
,"1.4e1.e7"+0
ou"14+13"+0
serão todos iguais a 14).Explicação basta usar um RegEx para verificar a presença de caracteres que não são dígitos nem ponto flutuante, sinal, etc.
adicionar
ou
à regra.
Ou você pode usar uma comparação
NF
se for a última coluna, como no seu exemplo.