方便地解析带有单位后缀的数字?


10

假设您的数据量具有人类可以理解的格式,例如的输出du -h,并希望进一步处理这些数字。假设您要通过grep传递数据,以对该数据的子集求和。您可以在许多从未见过的系统上临时执行此操作,并且只有很少的实用程序。您需要所有标准10 ^ n后缀的后缀转换。

是否存在一个gnu-linux实用程序将流水线中的后缀数字转换为实数?您是否编写了一个bash函数来执行此操作,或者是否编写了一些容易记住的perl,而不是使用一定长度的regex替换或几个sed步骤?

38M     /var/crazyface/courses/200909-90147
2.7M    /var/crazyface/courses/200909-90157
1.1M    /var/crazyface/courses/200909-90159
385M    /var/crazyface/courses/200909-90161
1.3M    /var/crazyface/courses/200909-90169
376M    /var/crazyface/courses/200907-90171
8.0K    /var/crazyface/courses/200907-90173
668K    /var/crazyface/courses/200907-90175
564M    /var/crazyface/courses/200907-90178
4.0K    /var/crazyface/courses/200907-90179

| grep 200907 | <amazing suffix conversion> | awk '{s+=$1} END {print s}'


相关参考:


2
您很少需要使用grep和awk。如果您使用的是awk,请使用awk。只需/200907/在您的每行代码前面添加即可,例如awk '/200907/{s+=$1} END {print s}'
Tony

Answers:


14

根据我对您链接到的以下问题之一的回答:

awk '{
    ex = index("KMGTPEZY", substr($1, length($1)))
    val = substr($1, 0, length($1) - 1)

    prod = val * 10^(ex * 3)

    sum += prod
}
END {print sum}'

使用的另一种方法:

sed 's/G/ * 1000 M/;s/M/ * 1000 K/;s/K/ * 1000/; s/$/ +\\/; $a0' | bc

对于第二种方法,如果后缀为s怎么办?
djuarez

@djuarez:s代表什么乘数?
暂停,直到另行通知。

没有,只是推断其他单位案例。
djuarez

@djuarez:那没有任何意义。这个答案是关于SI后缀的,而不是一般单位(也许是秒)。为了sed在我的答案中扩展命令,您将添加一些子句以处理我在awk命令中显示的其他SI后缀。s/T/ * 1000 G;例如,在开始处添加将增加TB级。
暂停,直到另行通知。

3

您可以使用perl正则表达式来执行此操作。例如,

$value = 0;
if($line =~ /(\d+\.?\d*)(\D+)\s+/) {
   $amplifier = 1024 if ($2 eq 'K');
   $amplifier = 1024 * 1024 if ($2 eq 'M');
   $amplifier = 1024 * 1024 * 1024 if ($2 eq 'G');
   $value = $1 * $amplifier;
}

这是一个简单的脚本。您可以将其视为起点。希望对您有所帮助!


确实,这是一种方式。我还找到了stackoverflow.com/questions/2557649/…
豆子

3

就个人而言,我只是不会首先使用-h标志。“人类可读”版本将数字四舍五入,当您转换回来时,数字将需要再次四舍五入,甚至变得更不准确。(例如2.7MiB是2831155.2字节。您对字节的其他0.8字节做了什么处理?!)

否则,您可以要求units将MiB / GiB / KiB转换为“ B”,它将处理此问题,但是您必须执行类似的操作(假设您的输出已制表,否则为cut适当)

{your output} | cut -f1 '-d{tab}' | xargs -L 1 -I {} units -1t {}iB B | awk '{s+=$1}END{printf "%d\n",s}'

众所周知,这会损失精度。将输入补充到单位上也可以..但是我发现units最小发行版中缺少内容!我认为,如果我们完全掌控一切,我们将采取不同的做法。
豆子

2
VALUE=$1

for i in "g G m M k K"; do
        VALUE=${VALUE//[gG]/*1024m}
        VALUE=${VALUE//[mM]/*1024k}
        VALUE=${VALUE//[kK]/*1024}
done

[ ${VALUE//\*/} -gt 0 ] && echo VALUE=$((VALUE)) || echo "ERROR: size invalid, pls enter correct size"
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.