![将 awk printf 字符串转换为十进制](https://linux22.com/image/137472/%E5%B0%86%20awk%20printf%20%E5%AD%97%E7%AC%A6%E4%B8%B2%E8%BD%AC%E6%8D%A2%E4%B8%BA%E5%8D%81%E8%BF%9B%E5%88%B6.png)
任务:
stdout 以十进制形式从顶部输出平均负载(例如 0.23)
细节:
我需要将此脚本解析为 Chef 的 inspec 并检查其结果是否大于/小于某些内容,例如:
describe command("top -b -n 1 | awk '/load average/ { sub(/,/,\".\",$10); printf \"%f\n\",$10}'") do
its("stdout") { should eq 0.00 }
end
此示例返回“”
但现在当我想到这一点时,我可以与中的文件进行比较/proc/loadavg
进步
使用此资源:用top获取平均负载
通过这个命令,我得到了输出的良好表示,但它是一个字符串,我无法用它进行任何数学运算:
martin@martinv-pc:~$ top -b -n 1 | awk '/load average/ { printf "%s\n", $10}'
0,63,
但是当我尝试将 printf 更改为十进制/浮点时,出现错误:
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
无法回声,尝试剪切,馊主意-- 不工作:
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
另一种尝试:
martin@martinv-pc:~$ top -b -n 1 | awk '/load average/ BEGIN { printf "%.f\n", $10};'
awk: line 1: syntax error at or near BEGIN
问题:
如何将字符串值转换为小数/浮点/整数?
ps -o user,rss
输出:
[vagrant@localhost ~]$ ps -o user,rss
USER RSS
vagrant 736
vagrant 1080
答案1
答案是使用--use-lc-numeric
gawk 选项。
--使用-lc-数字
这会强制 gawk 在解析输入数据时使用语言环境的小数点字符。尽管 POSIX 标准要求这种行为,并且 gawk 在 --posix 生效时也会这样做,但默认情况下是遵循传统行为并使用句点作为小数点,即使在句点不是小数点字符的语言环境中也是如此。此选项会覆盖默认行为,而没有 --posix 选项的完全严格的严格性。
在你的情况下,这个命令应该有效:
top -b -n 1 | awk --use-lc-numeric '/load average/ { printf "%f\n", $10}'
答案2
,
您可能正在使用具有小数点分隔符的区域设置。您可以尝试以下任何一种方法:
使用 C 语言环境
top
:LC_ALL=C top -b -n 1 | awk '/load average/ { printf "%f\n",$10}'
这不仅解决了句号与逗号的问题,而且还避免了文本问题,例如
load average
翻译成用户语言的问题。将逗号替换为点:
top -b -n 1 | awk '/load average/ { sub(/,/,".",$10); printf "%f\n",$10}'
对于 GNU
awk
,使用--use-lc-numeric
标志由@Leo推荐或使用POSIXLY_CORRECT=1 awk
.或者使用 POSIX 兼容的
awk
实现,例如真正的 awk 默认情况下,它应该根据区域设置规则解析和打印数字。
请注意,获取平均负载的更便携的命令是uptime
。
答案3
任务:
sdout 以十进制形式从顶部开始的平均负载(例如 0.23)
解决方案:
top -b -n 1 | perl -lane 'print "$1.$2" if /load average: (\d+)[,.](\d+)/'
笔记:
这将检索 1m 负载平均值。看起来这就是你想要的,但你应该说清楚。如果需要,可以轻松修改代码以检索 5 分钟或 15 分钟甚至全部三分钟内的负载平均值。
正如所指出的@特登,可能是比本例uptime
更好的起点。top
前两行之后,您隐晦地描述你想对结果做什么。您想要采取的后续步骤应该成为新问题的主题。
在 Perl 中,数字会自动转换为字符串,反之亦然。可以对表示数字的字符串执行任何数值运算。例如print "$1.$2"+11.11
问题2:
这一部分是关于第二个问题,即完全不相关到第一个。
我敦促OP单独发布这个问题。
如何将字符串值转换为小数/浮点/整数?
解决方案:
to_i
使用或将字符串转换为数字格式to_f
。
例子:
describe command("echo 1.00") do
its("stdout.to_f") { should be < 1.03 }
end
解释:
非常合理的是,stdout 被视为字符串。也非常合理,数字比较要求两个数字是...数字。幸运的是,可以使用方便的 Ruby 字符串方法来完成转换:to_i
、to_f
和。to_r
to_c
答案4
您的问题是提取的字段使用逗号作为小数点分隔符,而 awk 期望浮点数使用点。
这重现了您的问题:
$ 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
如您所见,数字使用逗号作为小数点分隔符。你需要类似的东西:
$ 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
但这取决于locale -a
您的系统上安装了哪些区域设置(使用 进行检查)。区域C
设置始终可用。
$ 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
但是使用 top 只提取第一行就有点矫枉过正了。更好地利用正常运行时间:
$ LC_ALL=C uptime
08:42:08 up 1 day, 10:27, 5 users, load average: 0.35, 0.37, 0.31
但更好的是,阅读/proc/loadavg
文件
$ cat /proc/loadavg
0.29 0.34 0.30 1/468 15084
顺便说一下,这不受语言环境的影响。第一个数字是 1 分钟负载平均值,只需选择它并以任何格式打印:
$ awk '{printf( "%s\n %f\n %d\n", $1, $1, $1 )}' /proc/loadavg
0.35
0.350000
0
对于 1、5 和 15 分钟负载平均使用:
$ awk '{printf( "%7.3f %7.3f %5.2f\n", $1, $2, $3 )}' /proc/loadavg
0.150 0.340 0.33