3

客观的

Linux 上,我试图获得一个代表可用系统内存的最终用户友好字符串。

例子:

Your computer has 4 GB of memory.

成功标准

我认为这些方面最终用户友好(您可能不同意):

  • 1G1.0G( 1Vs 1.0)更具可读性

  • 1GB1G( GBVs G)更具可读性

  • 1 GB1GBspace-separated度量单位)更具可读性

  • memoryRAM,DDRDDR3(没有行话)更具可读性

初始点

procps-ng免费实用程序有一个供人类使用的选项:

-h, --human
    Show all output fields automatically scaled to shortest three digit unit
    and display the units of print out.  Following units are used.
        B = bytes
        K = kilos
        M = megas
        G = gigas
        T = teras
    If unit is missing, and you have petabyte of RAM or swap, the number is
    in terabytes and columns might not be aligned with header.

所以我决定从那里开始:

> free -h
             total       used       free     shared    buffers     cached
Mem:          3.8G       1.4G       2.4G         0B       159M       841M
-/+ buffers/cache:       472M       3.4G
Swap:         4.9G         0B       3.9G

3.8G听起来很有希望,所以我现在要做的就是......

所需步骤

  • 过滤包含人类可读字符串的行的输出(即Mem:

  • 从行中间挑出内存总量(即3.8G

  • 解析出数量和度量单位(即3.8G

  • 根据我的喜好格式化和显示字符串(例如GGB,...)

我的尝试

free -h | \
  awk  '/^Mem:/{print $2}' | \
    perl -ne '/(\d+(?:\.\d+)?)(B|K|M|G|T)/ && printf "%g %sB\n", $1, $2'

输出:

3.8 GB

所需的解决方案

  • 我宁愿只使用gawk,但我不知道如何

  • 使用更好的,甚至规范的方法来解析字符串中的“浮点数”

  • 我不介意“只是公认的大小字母”的挑剔(B|K|M|G|T)匹配,即使这会因引入新尺寸而不必要地破坏匹配

  • 我习惯%g输出4.0as 4,您可能不同意,这取决于您对这些评论的看法:https ://unix.stackexchange.com/a/70553/10283 。

我的问题,总结

  • 你可以只做上面的awk吗?
  • perl能写得更优雅,保持严格吗?

记住:

I am a beginner robot. Here to learn. :]

我从安迪·莱斯特那里学到的

为了我自己的利益,在这里总结一下:如果可以的话,巩固学习。

例如,这个gawk

echo foo bar baz | awk '{print $2}'

在perl中可以这样写:

echo foo bar baz | perl -ane 'print "$F[1]\n";'

除非有与 gawk 等价的东西,否则--field-separator我想我还是更喜欢 gawk ,尽管在 perl 中做所有事情当然既干净又高效。(有没有等价物?)


编辑:实际上,这证明存在,-F就像在gawk中一样:

echo ooxoooxoooo | perl -Fx -ane 'print join "\n", @F'

输出:

oo
ooo
oooo

  • perl有一个-l选项,这真是太棒了:将其视为Pythonstr.rstrip(如果您不是Python负责人,请参阅链接)的有效性,会自动为您$_重新附加\n

谢谢,安迪!


4

3 回答 3

3

是的,我确信你可以只使用 awk,但我是一个 Perl 人,所以这就是你只使用 Perl 的方法。

而不是(B|K|M|G|T)使用[BKMGT].

使用 Perl-l自动从输入中去除换行符并将它们添加到输出中。

我认为没有任何理由让 Awk 做一些剥离,而让 Perl 做剩下的。您可以使用 Perl 的 -a 自动拆分字段。

我不知道输出free -h到底是什么(我free没有-h选择)所以我猜这个

free -h | \
perl -alne'/^Mem:/ && ($F[1]=~/(\d+(?:\.\d+)?)[BKMGT]/) && printf( "%g %sB", $1, $2)'
于 2013-03-30T02:38:48.733 回答
2

一个awk(实际上是gawk)解决方案

free -h | awk 'FNR == 2 {if (match($2,"[BKMGT]$",a)) r=sprintf("%.0f %sB",substr($2,0,RSTART-1), a[0]); else r=$2 " B";print "Your computer has " r " of memory."}'

或为便于阅读而分解

free -h | awk 'FNR == 2 {if (match($2,"[BKMGT]$",a)) r=sprintf("%.0f %sB",
          substr($2,0,RSTART-1), a[0]); else r=$2 " B";
          print "Your computer has " r " of memory."}'

在哪里

  • FNR是第 n(如果2{}命令)
  • $2第二个字段
  • if(条件)命令;else命令;
  • match(字符串,正则表达式,匹配数组)。正则表达式说“必须以 BKMGT 之一结尾”
  • r=sprintf将变量设置rsprintf%.0f无小数浮动
  • RSTART告诉匹配发生的位置,a[0]是第一个匹配

上面例子的输出

Your computer has 4 GB of memory.
于 2013-03-30T18:52:20.910 回答
0

另一个冗长的 Perl 答案:

free -b | 
perl -lane 'if(/Mem/){ @u=("B","KB","MB","GB"); $F[2]/=1024, shift @u while ($F[2]>1024); printf("%.2f %s", $F[2],$u[0])}'
于 2013-03-30T03:02:30.673 回答