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
精彩评论