有没有标准工具它将字节的整数计数转换为人类可读的最大可能单位大小的计数,同时保持数值在 1.00 和 1023.99 之间?
我有自己的 bash/awk 脚本,但我正在寻找一个标准工具,在许多/大多数发行版上都可以找到...更普遍可用的东西,并且理想情况下具有简单的命令行参数,和/或可以接受管道输入。
以下是我正在寻找的输出类型的一些示例。
1 Byt
173.00 KiB
46.57 MiB
1.84 GiB
29.23 GiB
265.72 GiB
1.63 TiB
这里是字节人类脚本(用于上述输出)
awk -v pfix="$1" -v sfix="$2" 'BEGIN {
split( "Byt KiB MiB GiB TiB PiB", unit )
uix = uct = length( unit )
for( i=1; i<=uct; i++ ) val[i] = (2**(10*(i-1)))-1
}{ if( int($1) == 0 ) uix = 1; else while( $1 < val[uix]+1 ) uix--
num = $1 / (val[uix]+1)
if( uix==1 ) n = "%5d "; else n = "%8.2f"
printf( "%s"n" %s%s\n", pfix, num, unit[uix], sfix )
}'
更新 这是一个修改版本吉尔斯的脚本,如对他的答案的评论中所述..(修改以适合我喜欢的外观)。
awk 'function human(x) {
s=" B KiB MiB GiB TiB EiB PiB YiB ZiB"
while (x>=1024 && length(s)>1)
{x/=1024; s=substr(s,5)}
s=substr(s,1,4)
xf=(s==" B ")?"%5d ":"%8.2f"
return sprintf( xf"%s\n", x, s)
}
{gsub(/^[0-9]+/, human($1)); print}'
答案1
POSIX 中没有这样的东西,但现代 GNU coreutils 中有一个数字格式化程序:numfmt
至少接近您的示例输出。 GNU coreutils ≥8.24(2015 年,因此存在于所有非嵌入式 Linux 上,除了具有非常长期支持周期的最旧版本之外):
$ numfmt --to=iec-i --suffix=B --format="%9.2f" 1 177152 48832200 1975684956
1.00B
173.00KiB
46.58MiB
1.84GiB
许多旧的 GNU 工具可以生成这种格式GNU sort 可以对带有单位的数字进行排序自 coreutils 7.5(2009 年 8 月,因此几乎所有非嵌入式 Linux 发行版上都存在)开始。
我发现你的代码有点复杂。这是一个更清晰的 awk 版本(输出格式并不完全相同):
awk '
function human(x) {
if (x<1000) {return x} else {x/=1024}
s="kMGTEPZY";
while (x>=1000 && length(s)>1)
{x/=1024; s=substr(s,2)}
return int(x+0.5) substr(s,1,1)
}
{sub(/^[0-9]+/, human($1)); print}'
答案2
从 v. 开始8.21
,coreutils
包括numfmt
:
numfmt
读取各种表示形式的数字并根据要求重新格式化它们。
最常见的用法是将数字与数字相互转换 人类表示。
例如
printf %s\\n 5607598768908 | numfmt --to=iec-i
5.2钛
提供了各种其他示例(包括过滤、输入/输出处理等)这里。
此外,从coreutils
v.开始8.24
,numfmt
可以处理字段范围规格类似于 的多个字段,并支持使用选项cut
设置输出精度, 例如--format
numfmt --to=iec-i --field=2,4 --format='%.3f' <<<'tx: 180000 rx: 2000000'
发送:175.782Ki 接收:1.908Mi
答案3
这是仅 bash 选项,没有bc
或任何其他非内置选项,+ 十进制格式和二进制单位。
# Converts bytes value to human-readable string [$1: bytes value]
bytesToHumanReadable() {
local i=${1:-0} d="" s=0 S=("Bytes" "KiB" "MiB" "GiB" "TiB" "PiB" "EiB" "YiB" "ZiB")
while ((i > 1024 && s < ${#S[@]}-1)); do
printf -v d ".%02d" $((i % 1024 * 100 / 1024))
i=$((i / 1024))
s=$((s + 1))
done
echo "$i$d ${S[$s]}"
}
例子:
$ bytesToHumanReadable 123456789
117.73 MiB
$ bytesToHumanReadable 1000000000000 # '1TB of storage'
931.32 GiB # 1TB of storage
$ bytesToHumanReadable
0 Bytes
$ bytesToHumanReadable 9223372036854775807
7.99 EiB
应该在任何版本的 Bash 上表现良好(包括 MSYSGit 的 Bash for Windows)。
答案4
这是受 Peter.O 对 Gilles 的 awk 脚本的修改版本启发的完全重写。
变化:
- 修复了 Peter.O 的错误,他在查找大于 1 个字符的字符串时应该查找大于 4 个字符的字符串。由于该错误,他的代码不适用于 ZiB 单位。
- 删除一长串以空格分隔的单位大小的非常难看的硬编码。
- 添加命令行开关以启用/禁用填充。
- 添加命令行开关以从 base-1024 (KiB) 转换为 base-1000 (KB) 表示法。
- 将所有内容封装在一个易于使用的功能中。
- 我将其置于公共领域并欢迎广泛使用。
代码:
bytestohuman() {
# converts a byte count to a human readable format in IEC binary notation (base-1024), rounded to two decimal places for anything larger than a byte. switchable to padded format and base-1000 if desired.
local L_BYTES="${1:-0}"
local L_PAD="${2:-no}"
local L_BASE="${3:-1024}"
BYTESTOHUMAN_RESULT=$(awk -v bytes="${L_BYTES}" -v pad="${L_PAD}" -v base="${L_BASE}" 'function human(x, pad, base) {
if(base!=1024)base=1000
basesuf=(base==1024)?"iB":"B"
s="BKMGTEPYZ"
while (x>=base && length(s)>1)
{x/=base; s=substr(s,2)}
s=substr(s,1,1)
xf=(pad=="yes") ? ((s=="B")?"%5d ":"%8.2f") : ((s=="B")?"%d":"%.2f")
s=(s!="B") ? (s basesuf) : ((pad=="no") ? s : ((basesuf=="iB")?(s " "):(s " ")))
return sprintf( (xf " %s\n"), x, s)
}
BEGIN{print human(bytes, pad, base)}')
return $?
}
测试用例(如果您想查看输出):
bytestohuman 1; echo "${BYTESTOHUMAN_RESULT}.";
bytestohuman 500; echo "${BYTESTOHUMAN_RESULT}.";
bytestohuman 1023; echo "${BYTESTOHUMAN_RESULT}.";
bytestohuman 1024; echo "${BYTESTOHUMAN_RESULT}.";
bytestohuman 1500; echo "${BYTESTOHUMAN_RESULT}.";
bytestohuman 150000; echo "${BYTESTOHUMAN_RESULT}.";
bytestohuman 150000000; echo "${BYTESTOHUMAN_RESULT}.";
bytestohuman 150000000000; echo "${BYTESTOHUMAN_RESULT}.";
bytestohuman 150000000000000; echo "${BYTESTOHUMAN_RESULT}.";
bytestohuman 150000000000000000; echo "${BYTESTOHUMAN_RESULT}.";
bytestohuman 150000000000000000000; echo "${BYTESTOHUMAN_RESULT}.";
bytestohuman 1 no 1000; echo "${BYTESTOHUMAN_RESULT}.";
bytestohuman 500 no 1000; echo "${BYTESTOHUMAN_RESULT}.";
bytestohuman 1023 no 1000; echo "${BYTESTOHUMAN_RESULT}.";
bytestohuman 1024 no 1000; echo "${BYTESTOHUMAN_RESULT}.";
bytestohuman 1500 no 1000; echo "${BYTESTOHUMAN_RESULT}.";
bytestohuman 150000 no 1000; echo "${BYTESTOHUMAN_RESULT}.";
bytestohuman 150000000 no 1000; echo "${BYTESTOHUMAN_RESULT}.";
bytestohuman 150000000000 no 1000; echo "${BYTESTOHUMAN_RESULT}.";
bytestohuman 150000000000000 no 1000; echo "${BYTESTOHUMAN_RESULT}.";
bytestohuman 150000000000000000 no 1000; echo "${BYTESTOHUMAN_RESULT}.";
bytestohuman 150000000000000000000 no 1000; echo "${BYTESTOHUMAN_RESULT}.";
bytestohuman 1 yes; echo "${BYTESTOHUMAN_RESULT}.";
bytestohuman 500 yes; echo "${BYTESTOHUMAN_RESULT}.";
bytestohuman 1023 yes; echo "${BYTESTOHUMAN_RESULT}.";
bytestohuman 1024 yes; echo "${BYTESTOHUMAN_RESULT}.";
bytestohuman 1500 yes; echo "${BYTESTOHUMAN_RESULT}.";
bytestohuman 150000 yes; echo "${BYTESTOHUMAN_RESULT}.";
bytestohuman 150000000 yes; echo "${BYTESTOHUMAN_RESULT}.";
bytestohuman 150000000000 yes; echo "${BYTESTOHUMAN_RESULT}.";
bytestohuman 150000000000000 yes; echo "${BYTESTOHUMAN_RESULT}.";
bytestohuman 150000000000000000 yes; echo "${BYTESTOHUMAN_RESULT}.";
bytestohuman 150000000000000000000 yes; echo "${BYTESTOHUMAN_RESULT}.";
bytestohuman 1 yes 1000; echo "${BYTESTOHUMAN_RESULT}.";
bytestohuman 500 yes 1000; echo "${BYTESTOHUMAN_RESULT}.";
bytestohuman 1023 yes 1000; echo "${BYTESTOHUMAN_RESULT}.";
bytestohuman 1024 yes 1000; echo "${BYTESTOHUMAN_RESULT}.";
bytestohuman 1500 yes 1000; echo "${BYTESTOHUMAN_RESULT}.";
bytestohuman 150000 yes 1000; echo "${BYTESTOHUMAN_RESULT}.";
bytestohuman 150000000 yes 1000; echo "${BYTESTOHUMAN_RESULT}.";
bytestohuman 150000000000 yes 1000; echo "${BYTESTOHUMAN_RESULT}.";
bytestohuman 150000000000000 yes 1000; echo "${BYTESTOHUMAN_RESULT}.";
bytestohuman 150000000000000000 yes 1000; echo "${BYTESTOHUMAN_RESULT}.";
bytestohuman 150000000000000000000 yes 1000; echo "${BYTESTOHUMAN_RESULT}.";
享受!