开发者

Unformat disk size strings

Is there some way to convert strings like 1K to 1000, 1M to 1000000 etc. with a single Bash command? I'd like to avoid being the one million and thirty-first guy to create a >10-line or >100-character one-liner hack for this. Something like iso2int开发者_开发技巧 5MB.

Edit: units -t '5MB' 'bytes works, but that tool is not available. Are there any simple ways to convert either 5M or 5MB and similar to bytes?

max's solution was elegant, but the shortest equivalent which would work in my case is at the very least sed -e 's/b//i;s/k/*1000/i;s/m/*1000000/i;s/g/*1000000000/i;s/t/*1000000000000/i' | bc.


Something like this?

$ echo "1K + 10M" | sed -e "s/K/*1024/g;s/M/*1024*1024/" | bc
10486784

Edit:

sed -e 's/t/kg/i;s/g/km/i;s/m/kk/i;s/k/*1000/ig;s/b//i' | bc


Edit:

My original answer is just silly. Here is a pure Bash solution based on max taldykin's sed/bc excellent answer.

s=21TB;(( $BASH_VERSINFO >= 4 ))&&s=${s^^};s=${s/B};s=${s/E/KP};s=${s/P/KT}; s=${s/T/KG};s=${s/G/KM};s=${s/M/KK};s=${s//K/*1024};printf "%'u\n" $((s))

This is longer than my original one-liner only by virtue of the fact that it includes case-insensitivity while the latter didn't (although it could and the function did). It's only about twice as long by character count as max's when adjusted for equivalent functionality.

Original:

Here is a pure Bash solution:

As a function (see below for a one-liner):

#!/bin/bash
# written by Dennis Williamson 2010-12-09
# for https://stackoverflow.com/questions/4399475/unformat-disk-size-strings
expandsi () {
    # set k to 1000 if that's your preference, p is a pattern to match unit chars
    local k=1024 p='E|P|T|G|M|K| '   # exa, peta, tera, giga, mega, kilo, bytes
    local b=$1 c e s=${p//|}         # s is the list of units
    (( $BASH_VERSINFO >= 4 )) && b=${b^^}  # toupper for case insensitivity
    b=${b%B*}                        # strip any trailing B from the input
    c=${b: -1}                       # get the unit character
    c=${c/%!($p)/ }                  # add a space if there's no unit char
    b=${b%@($p)*}                    # remove the unit character
    e=${s#*${c:0:1}}                 # index into the list of units
    # do the math, remove the single quote to omit the thousands separator
    printf "%'u\n" $((b * k**${#e}))
}

To test the function:

testvals='1 22 333 4444 '
testvals+='4B 44B 1000B '
testvals+='1M 1MB 987MB '
testvals+='1K 23KB 1KB 100K '
testvals+='10G 10GB 3333G '
testvals+='3T 12PB '
# exabytes is pushing it for Bash's int capacity
# on my system, printf "%'u\n" -1 gives 18,446,744,073,709,551,615
testvals+='15EB '

for i in $testvals
do
    expandsi $i
done

Results:

1
22
333
4,444
4
44
1,000
1,048,576
1,048,576
1,034,944,512
1,024
23,552
1,024
102,400
10,737,418,240
10,737,418,240
3,578,781,499,392
3,298,534,883,328
13,510,798,882,111,488
17,293,822,569,102,704,640

As promised, at long last, the one-liner version:

$ b=200GB k=1024 p='E|P|T|G|M|K| ';s=${p//|} b=${b%B*};c=${b: -1};c=${c/%!($p)/ };b=${b%@($p)*};e=${s#*${c:0:1}};printf "%'u\n" $((b * k**${#e}))
214,748,364,800
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜