Convertendo a string awk printf para decimal

3

Tarefa:

stdout a carga média do topo em uma forma decimal como (por exemplo, 0,23)

Detalhes:

Eu preciso analisar este script para inspec do Chef e verificar se o resultado é maior / menor que algo, por exemplo:

describe command("top -b -n  1  | awk  '/load average/ { sub(/,/,\".\",$10); printf \"%f\n\",$10}'") do
  its("stdout") { should eq 0.00 }    
end

Este exemplo retorna ""

Mas agora, quando penso nisso, posso comparar com um arquivo em /proc/loadavg

Progresso

Use este recurso: Agarre a média de carga com o topo

Com este comando, obtenho uma boa representação da saída, mas é uma string e não consigo fazer nenhuma operação matemática com ela:

martin@martinv-pc:~$ top -b -n  1  | awk '/load average/ { printf "%s\n", $10}'
0,63,

Mas quando tento alterar o printf para decimal / float, recebo um erro:

martin@martinv-pc:~$ top -b -n  1  | awk '/load average/ { printf "%f\n", $10}'
0.000000
martin@martinv-pc:~$ top -b -n  1  | awk '/load average/ { printf "%d\n", $10}'
0

Não é possível ecoar, tentou com recorte, má ideia - não funciona:

martin@martinv-pc:~$ top -b -n  1  | awk '/load average/ { printf "%s\n", $10}'|cut -c1-4
0,15
martin@martinv-pc:~$ top -b -n  1  | awk '/load average/ { printf "%s\n", $10}'|$((cut -c1-4))
-4: command not found

Outra tentativa:

martin@martinv-pc:~$ top -b -n  1  | awk '/load average/ BEGIN { printf "%.f\n", $10};'
awk: line 1: syntax error at or near BEGIN

Pergunta:

Como posso converter o valor da string para decimal / float / integer?

ps -o user,rss output:

[vagrant@localhost ~]$ ps -o user,rss
USER       RSS
vagrant    736
vagrant   1080
    
por murloc 25.07.2018 / 12:43

4 respostas

1

Tarefa:

sdout the load avg from top in a decimal form like(e.g 0.23)

Solução:

top -b -n  1  | perl -lane 'print "$1.$2" if /load average: (\d+)[,.](\d+)/'

Notas:

Isso recupera a média de carga de 1m. Parece que é isso que você quer, mas você deve declarar isso claramente. Se necessário, o código pode ser facilmente modificado para recuperar as médias de carga ao longo de 5 minutos ou 15 minutos, ou até mesmo todos os três.

Como apontado por @terdon , uptime pode ser um ponto de partida melhor do que top em neste caso.

Após as duas primeiras linhas, você obscuramente descreve o que deseja fazer com o resultado. As etapas subseqüentes que você deseja seguir devem ser assunto de novas perguntas.

Em Perl, os números são convertidos automaticamente em strings e vice-versa. Qualquer operação numérica pode ser executada em uma string representando um número. por exemplo. print "$1.$2"+11.11

Pergunta 2:

Esta parte é sobre a segunda questão, que é totalmente não relacionada para a primeira. Eu peço ao OP para postar esta questão separadamente .

How Can I convert the string value to decimal/float/integer ?

Melhor escrito como: Realizando comparações numéricas em strings com Chef 's InSpec .

Solução:

Converta a string em um formato numérico, com to_i ou to_f .

Exemplo:

describe command("echo 1.00") do
    its("stdout.to_f") { should be < 1.03 }
end

Explicação:

Muito razoavelmente, stdout é tratado como uma string. Também muito razoavelmente, as comparações numéricas exigem que os dois números sejam ... números. Felizmente, a conversão pode ser feita com os métodos úteis de string Ruby: to_i , to_f , to_r e to_c .

    
por 25.07.2018 / 15:18
2

De gawk: resumo de floats formatados com separador de vírgula :

A resposta é usar a opção --use-lc-numeric gawk.

--use-lc-numeric

This forces gawk to use the locale's decimal point character when parsing input data. Although the POSIX standard requires this behavior, and gawk does so when --posix is in effect, the default is to follow traditional behavior and use a period as the decimal point, even in locales where the period is not the decimal point character. This option overrides the default behavior, without the full draconian strictness of the --posix option.

No seu caso, este comando deve funcionar:

top -b -n 1 | awk --use-lc-numeric '/load average/ { printf "%f\n", $10}'

    
por 25.07.2018 / 12:49
2

Você provavelmente está usando uma localidade que tenha , como o separador decimal. Você pode tentar qualquer uma dessas abordagens:

  1. Use a localidade C para top :

    LC_ALL=C top -b -n  1  | awk  '/load average/ { printf "%f\n",$10}'
    

    Isso não apenas aborda o período versus o problema de vírgula, mas também evita problemas com texto como load average traduzido para o idioma do usuário.

  2. Substitua a vírgula por um ponto:

    top -b -n  1  | awk  '/load average/ { sub(/,/,".",$10); printf "%f\n",$10}'
    
  3. Com o GNU awk , use o --use-lc-numeric sinalizador sugerido pela @Leo ou use POSIXLY_CORRECT=1 awk .

  4. Ou use uma implementação awk compatível com POSIX como o One True awk que deve analisar e imprimir números de acordo com regras de localidade por padrão.

Observe que um comando mais portátil para obter a média de carga é uptime .

    
por 25.07.2018 / 13:03
1

Seu problema é que o campo extraído está usando a vírgula como separador decimal e o awk espera que os floats usem um ponto.

Isso reproduz seu problema:

$ LC_ALL=de_DE top -bn 1 | awk 'NR==1'
top - 08:37:07 up 1 day, 10:22,  5 users,  load average: 0,17, 0,24, 0,26

Como você pode ver, os números usam uma vírgula como separador decimal. Você precisa de algo semelhante a:

$ LC_ALL=en_US top -bn 1 | awk 'NR==1'
top - 08:38:28 up 1 day, 10:23,  5 users,  load average: 0.56, 0.34, 0.30

Mas isso dependerá de quais locales foram instalados (verifique com locale -a ) em seu sistema. Um C locale está sempre disponível.

$ LC_ALL=C top -bn 1 | awk 'NR==1'
top - 08:40:35 up 1 day, 10:25,  5 users,  load average: 0.50, 0.39, 0.31

Mas usar o topo para extrair apenas a primeira linha é um exagero. Melhor aproveitamento:

$ LC_ALL=C uptime
08:42:08 up 1 day, 10:27,  5 users,  load average: 0.35, 0.37, 0.31

Mas, melhor ainda, leia o arquivo /proc/loadavg

$ cat /proc/loadavg 
0.29 0.34 0.30 1/468 15084

Que, a propósito, não é afetado pela localidade. O primeiro número é a média de carga de 1 minuto, basta selecioná-lo e imprimir em qualquer formato:

$ awk '{printf( "%s\n %f\n %d\n", $1, $1, $1 )}' /proc/loadavg
0.35
0.350000
0

Para os 1, 5 e 15 minutos de uso médio de carga:

$ awk '{printf( "%7.3f %7.3f %5.2f\n", $1, $2, $3 )}' /proc/loadavg
 0.150   0.340  0.33
    
por 26.07.2018 / 14:53