68

给定文件的大小(以字节为单位),我想用IEC(二进制)前缀将其格式化为3 个有效数字,尾随零,例如 1883954 变为 1.80M。

bash 不支持浮点运算,所以我改用 awk。问题是我不知道如何保留尾随零。当前解决方案:

if [ $size -ge 1048576 ]
then
    size=$(awk 'BEGIN {printf "%.3g",'$size'/1048576}')M
elif [ $size -ge 1024 ]
then
    size=$(awk 'BEGIN {printf "%.3g",'$size'/1024}')K
fi

(文件不是那么大,所以我不必考虑更大的单位。)

编辑:这还有另一个问题。请参阅下面的 Adrian Frühwirth 的评论。

4

7 回答 7

140

你有什么理由不使用

ls -lh

命令 ?如果您使用的是最近几年发布的 Linux 系统,则您拥有此功能。

于 2013-04-06T18:36:26.590 回答
75

GNU Coreutils包含一个显然不为人知的小工具numfmt,用于进行数字转换,它可以满足您的需求:

$ numfmt --to=iec-i --suffix=B --format="%.3f" 4953205820
4.614GiB

我认为这很适合您的需求,并且不像其他答案那么大或笨拙。

如果您想要更强大的解决方案,请查看我的其他答案。

于 2013-12-12T01:27:18.393 回答
13
ls -lah /path/to/your/file | awk -F " " {'print $5'}
于 2015-02-22T21:00:54.960 回答
4

而不是使用lsandawk来获取文件大小,使用stat -c %s filename.ext. 它只输出数字,没有其他内容(至少在版本 8.21 上)。我不能使用numfmt,因为它是旧版本,似乎没有使用具有小数精度的 printf 语法。我改为使用下面的脚本。我使用最后一行来测试是否正在获取脚本。如果不是,我可以直接在命令行调用它。

#!/bin/bash

function getFriendlyFileSize() {
    OUT='/dev/null'
    [ "$#" == 0 ] && echo 'No number given' && return 1
    [ ! $(echo $1 | egrep -i '\-?[0-9]+') ] && echo 'Garbage data' && return 1

    if [ "$1" == '' -o "$1" -lt 0 ] 2>$OUT
    then
            echo '0 B'
            return 1
    else
            FSIZE=$1
    fi

    [ "$2" == '' ] && DECPTS=1 || DECPTS=$2

    KB=1024
    MB=1048576
    GB=1073741824
    TB=1099511627776
    PB=1125899906842624
    EB=1152921504606846976
    LM=9223372036854775807 # bash comparison limit = 2^63-1 (signed int?)

    [ "$FSIZE" -le 0 ] 2>$OUT && echo "0 B" && return
    [ "$FSIZE" -lt $KB ] 2>$OUT && echo "$FSIZE B" && return
    [ "$FSIZE" -lt $MB ] 2>$OUT && echo "$(echo "scale=$DECPTS;$FSIZE/$KB"|bc) KB" && return
    [ "$FSIZE" -lt $GB ] 2>$OUT && echo "$(echo "scale=$DECPTS;$FSIZE/$MB"|bc) MB" && return
    [ "$FSIZE" -lt $TB ] 2>$OUT && echo "$(echo "scale=$DECPTS;$FSIZE/$GB"|bc) GB" && return
    [ "$FSIZE" -lt $PB ] 2>$OUT && echo "$(echo "scale=$DECPTS;$FSIZE/$TB"|bc) TB" && return
    [ "$FSIZE" -lt $EB ] 2>$OUT && echo "$(echo "scale=$DECPTS;$FSIZE/$PB"|bc) PB" && return
    [ "$FSIZE" -le $LM ] 2>$OUT && echo "$(echo "scale=$DECPTS;$FSIZE/$EB"|bc) EB" && return
    [ "$?" -ne '0' ] 2>$OUT && echo "Bad input" && return 1
}

[[ $_ == $0 ]] && getFriendlyFileSize $1 $2
于 2017-02-20T04:00:23.487 回答
3

我知道这有点晚了。但可能有人会觉得它有用。

答案很简单,就是在你的脚本中使用%.2f而不是。%.3g()


测试:

#!/bin/bash

size=1883954

if [ $size -ge 1048576 ]
then
    size=$(awk 'BEGIN {printf "%.2f",'$size'/1048576}')M
elif [ $size -ge 1024 ]
then
    size=$(awk 'BEGIN {printf "%.2f",'$size'/1024}')K
fi

echo $size

输出:

1.80M
于 2015-11-11T15:24:12.450 回答
2

如果您不介意使用,bc那么以下内容将有助于进行浮点运算。scale可以根据您要打印的许多数字根据您的需要进行更改。

size=1883954

if [ $size -ge 1048576 ]
then
    size=$(echo "scale=2;$size/1048576"| bc)M
elif [ $size -ge 1024 ]
then
    size=$(echo "scale=2;$size/1024" | bc)K
fi

echo $size
于 2013-04-06T18:21:23.380 回答
0

如果你碰巧有Qalculate!安装(顺便说一句很棒),有一个简单的技巧:

human_readable="$( qalc -t set "precision $precision" "${in_bytes}B" )"

例子:

$ qalc -t -set "precision 3" 5264334820B
5.26 GB

它是 shell 脚本中非常非常强大的工具,因为它甚至可以简化公式、求解未知数等等。

$ qalc -t "e^(i*x)=-1"
x = 3.1415927

如果您想要一个更简单、重量更轻的解决方案,请查看我的其他答案。

于 2013-12-12T00:28:51.603 回答