将带有后缀的文件大小转换为字节的最简单方法

时间:2013-07-12 13:20:37

标签: shell

标题说明了这一切,但我目前正在使用带有case语句的简单函数将人类可读的文件大小字符串转换为字节大小。它运行得很好,但是移植到其他代码中有点笨拙,所以我很想知道是否有一个shell脚本可以使用的广泛可用的命令呢?

基本上我想要取“100g”或“100gb”这样的字符串并将它们转换成字节。

我目前正在做以下事情:

to_bytes() {
    value=$(echo "$1" | sed 's/[^0123456789].*$//g')
    units=$(echo "$1" | sed 's/^[0123456789]*//g' | tr '[:upper:]' '[:lower:]')

    case "$units" in
        t|tb)   let 'value *= 1024 * 1024 * 1024 * 1024'    ;;
        g|gb)   let 'value *= 1024 * 1024 * 1024'   ;;
        m|mb)   let 'value *= 1024 * 1024'  ;;
        k|kb)   let 'value *= 1024' ;;
        b|'')   let 'value += 0'    ;;
        *)
                value=
                echo "Unsupported units '$units'" >&2
        ;;
    esac

    echo "$value"
}

对于使用文件的脚本而言,我认为这是相当常见的东西似乎有点矫枉过正;很常见的事情可能存在更快地做到这一点。

如果没有广泛可用的解决方案(即 - 大多数unix和linux版本),那么我仍然会欣赏任何优化上述功能的技巧,因为我希望它能够更小,更容易重复使用。 / p>

6 个答案:

答案 0 :(得分:3)

toBytes() {
 echo $1 | echo $((`sed 's/.*/\L\0/;s/t/Xg/;s/g/Xm/;s/m/Xk/;s/k/X/;s/b//;s/X/ *1024/g'`))
}

答案 1 :(得分:2)

这是我写的东西。它支持kKBKiB。 (它不区分2的幂和10个后缀的幂,但是,1KB = 1000字节,1KiB = 1024字节。)

#!/bin/bash

parseSize() {(
    local SUFFIXES=('' K M G T P E Z Y)
    local MULTIPLIER=1

    shopt -s nocasematch

    for SUFFIX in "${SUFFIXES[@]}"; do
        local REGEX="^([0-9]+)(${SUFFIX}i?B?)?\$"

        if [[ $1 =~ $REGEX ]]; then
            echo $((${BASH_REMATCH[1]} * MULTIPLIER))
            return 0
        fi

        ((MULTIPLIER *= 1024))
    done

    echo "$0: invalid size \`$1'" >&2
    return 1
)}

注意:

  • 利用bash的=~正则表达式运算符,该运算符将匹配项存储在名为BASH_REMATCH的数组中。
  • 注意功能体周围巧妙隐藏的括号。他们在那里阻止shopt -s nocasematch泄漏出来。

答案 2 :(得分:2)

请参见man numfmt

# numfmt --from=iec 42 512K 10M 7G 3.5T
42
524288
10485760
7516192768
3848290697216

# numfmt --to=iec 42 524288 10485760 7516192768 3848290697216
42
512K
10M
7.0G
3.5T

答案 3 :(得分:0)

不知道这是否可以:

awk 'BEGIN{b=1;k=1024;m=k*k;g=k^3;t=k^4}
/^[0-9.]+[kgmt]?b?$/&&/[kgmtb]$/{
    sub(/b$/,"")
        sub(/g/,"*"g)
        sub(/k/,"*"k)
        sub(/m/,"*"m)
        sub(/t/,"*"t)
"echo "$0"|bc"|getline r; print r; exit;}
{print "invalid input"}'
  • 这只处理单行输入。如果需要多行,请移除exit
  • 仅检查模式[kgmt]和可选b。例如kib, mib会失败。目前也仅适用于小写。

e.g:

kent$  echo "200kb"|awk 'BEGIN{b=1;k=1024;m=k*k;g=k^3;t=k^4}                                                                                                                
/^[0-9.]+[kgmt]?b?$/&&/[kgmtb]$/{
    sub(/b$/,"")
        sub(/g/,"*"g)
        sub(/k/,"*"k)
        sub(/m/,"*"m)
        sub(/t/,"*"t)
"echo "$0"|bc"|getline r
print r; exit
}{print "invalid input"}'
204800

答案 4 :(得分:0)

好吧,所以听起来没有任何内置或广泛可用,这是一个耻辱,所以我已经去减少功能的大小,并提出了只有4行长的东西,虽然这是一个非常复杂的四行!

我不确定它是否适合作为我原始问题的答案,因为它不是我称之为最简单的方法,但我想把它放在以防万一有人认为它是一个有用的解决方案,它确实具有非常短的优势。

#!/bin/sh
to_bytes() {
    units=$(echo "$1" | sed 's/^[0123456789]*//' | tr '[:upper:]' '[:lower:]')
    index=$(echo "$units" | awk '{print index ("bkmgt kbgb  mbtb", $0)}')
    mod=$(echo "1024^(($index-1)%5)" | bc)
    [ "$mod" -gt 0 ] && 
        echo $(echo "$1" | sed 's/[^0123456789].*$//g')"*$mod" | bc
}

为了快速总结它是如何工作的,它首先从给定的字符串中删除数字,并强制为小写。然后使用awk从有效后缀的结构化字符串中获取扩展的索引。需要注意的是,字符串被排列为五的倍数(因此如果添加更多扩展,则需要加宽),例如k和kb分别位于索引2和7处。 然后将索引减1并以5为模,因此k和kb都变为1,m和mb变为2等等。然后用它来提高1024作为功率来获得以字节为单位的大小。如果扩展名无效,则将解析为零值,并且b(或无)的扩展名将计算为1。 只要mod大于零,输入字符串就会减少到只有数字部分并乘以修饰符才能得到最终结果。

实际上,如果我使用的是PHP,Java等语言,我可能会解决这个问题,在shell脚本中组合起来只是一个奇怪的事情。

我仍然非常感谢任何简化!

答案 5 :(得分:0)

另一种变体,使用更简单的T / G / M / K解析器添加对十进制值的支持,可以从更简单的Unix程序中找到输出。

to_bytes() {
value=$(echo "$1" | sed -e 's/K//g' | sed -e 's/M//g' | sed -e 's/G//g' | sed -e 's/T//g' )
units=$(echo -n "$1" | grep -o .$ )
    case "$units" in
        T)   value=$(bc <<< "scale=2; ($value * 1024 * 1024 * 1024 * 1024)")    ;;
        G)   value=$(bc <<< "scale=2; ($value * 1024 * 1024 * 1024)")   ;;
        M)   value=$(bc <<< "scale=2; ($value * 1024 * 1024)")  ;;
        K)   value=$(bc <<< "scale=2; ($value * 1024)") ;;
        b|'')   let 'value += 0'    ;;
        *)
                value=
                echo "Unsupported units '$units'" >&2
        ;;
    esac
echo "$value"
}