假设我有一堆表示内存量的数字,例如以“86k
或”320m
或“或”的形式书写1.7g
。如何在命令行中计算它们的总和,并获得人类可读的结果?
能够计算减法也很好。完美的工具将处理多组符号(例如1g
/ 1G
/ 1GB
/ 1Go
/ 1GiB
/ 1.7Gio
)及其含义(二进制或十进制乘数)。
我正在寻找一个纯粹的计算器。这些数字不一定是我磁盘上某些文件的大小,因此诸如find
、stat
或 之du
类的工具不是一种选择。
这显然很容易实现(在精度方面有一些障碍),但如果这还不存在,我会被诅咒!
一点自我提升:我们编写了一个名为libbytesize的库来使用 C 和 Python 进行这些计算,并且它还有一个名为bscalc的命令行工具
$ bscalc "5 * (100 GiB + 80 MiB) + 2 * (300 GiB + 15 GiB + 800 MiB)"
1215425413120 B
1186938880.00 KiB
1159120.00 MiB
1131.95 GiB
1.11 TiB
Run Code Online (Sandbox Code Playgroud)
该库打包在大多数发行版中,不幸的是该工具不是。它在 Fedoralibbytesize-tools
和 SuSE 中bscalc
,但不在 Debian/Ubuntu 中。
在 中zsh
,您可以定义一个数学函数,如:
() {
typeset -gA bsuffix
local n=1 ni=1 s
for s (k m g t p e) {
(( n *= 1000 )); (( ni *= 1024 ))
(( bsuffix[$s] = bsuffix[${s}ib] = bsuffix[${s}io] = ni ))
(( bsuffix[${s}b] = bsuffix[${s}o] = n ))
}
}
b() {
set -o localoptions -o extendedglob
local s=${(M)1%(#i)(${(j:|:k)~bsuffix})}
(( ${1%$s} * ${bsuffix[$s:l]-1} ))
}
functions -Ms b
Run Code Online (Sandbox Code Playgroud)
然后,你可以使用b(1G)
,b(1mB)
在任何zsh的算术表达式,像(( .... ))
,$(( ... ))
,$array[...]
,等,或在zcalc
:
$ <<< $((b(86k) + b(320mb) + b(1.7gio)))
2145449164.8
$ autoload zcalc
$ zcalc
1> b(86k) + b(320mb) + b(1.7gio)
2.14545e+09
2> :sci 15
2145449164.8
$ echo $(( b(infeo) ))
Inf
Run Code Online (Sandbox Code Playgroud)
(请注意,我们在b
和B
(或o
/ O
)之间没有区别,匹配不区分大小写。它不被解释为bit与byte)。
另一种方法可能是让b()
函数将整个表达式作为参数,并将所有后缀替换为* $bsuffix[<suffix>]
b() {
set -o localoptions -o extendedglob
local s=${(M)1%(#i)(${(j:|:k)~bsuffix})}
(( ${1//(#bi)([0-9.][[:blank:]]#)(${(j:|:k)~bsuffix})/$match[1] * $bsuffix[$match[2]:l] } ))
}
Run Code Online (Sandbox Code Playgroud)
进而:
$ echo $(( b(1m + 1Mb) ))
2048576
Run Code Online (Sandbox Code Playgroud)
虽然存在e
/ E
( exa )的问题,但它在工作中放置了一个扳手,因为它1e-3GB
不会被解释0.001 * 1000000000
为1 * 1152921504606846976 - 3 * 1000000000
.
在任何支持浮点运算(ksh93、zsh、yash)的 shell 中,你总是可以定义:
K=1024 M=$((K * K)) G=$((M * K)) T=$((G * K)) P=$((T * K)) E=$((P * K))
KiB=$K MiB=$M GiB=$G TiB=$T PiB=$P EiB=$E
KB=1000 MB=$((KB*KB)) GB=$((MB*KB)) TB=$((GB*KB)) PB=$((TB*KB)) EB=$((PB*KB))
Run Code Online (Sandbox Code Playgroud)
或者打高尔夫球:
K=1024 EiB=$((E=K*(P=PiB=K*(T=TiB=K*(G=GiB=K*(M=MiB=K*K))))))
KB=1000 EB=$((EB=KB*(PB=KB*(TB=KB*(GB=KB*(MB=KB*KB))))))
Run Code Online (Sandbox Code Playgroud)
和写 $(( 1.1*GB + 5*K ))
要在输出上添加后缀,您可以使用 GNU numfmt
:
$ human() numfmt --field=- --to=iec --suffix=iB
$ echo $(( b(1m + 1Mb) )) | human
2.0MiB
Run Code Online (Sandbox Code Playgroud)
有Bcal。
$ bcal -m "(5kib+2mib)/2"
1051136 B
$ bcal -m "(5kb+2mb)/2"
1002500 B
Run Code Online (Sandbox Code Playgroud)
该-m
标志用于简要输出。删除它会详细输出基数 2(KiB、MiB、GiB、TiB)和基数 10(kB、MB、GB、TB)的结果。
它不理解86k
or320m
或1.7g
,毕竟那些不是正确的字节单位。在这种情况下,您可以使用 Sedb
在每个字母之后添加,然后将其通过管道传输到bcal
:
$ cat file
1.7g+320m+86k
$ sed 's/[gmk]/&b/g' file | bcal -m
bcal> 1.7gb+320mb+86kb
2020086000 B
Run Code Online (Sandbox Code Playgroud)
您也可以在交互模式下使用它。