2010-12-09 30 views
3

Existe-t-il un moyen de convertir des chaînes telles que 1K en 1000, 1M en 1000000 etc. avec une seule commande Bash? Je voudrais éviter d'être le millionième et le trente et unième gars à créer un hack à une ligne de plus de 10 lignes ou 100 caractères. Quelque chose comme iso2int 5MB.Chaînes de taille de disque Unformat

Modifier: units -t '5MB' 'bytes fonctionne, mais cet outil n'est pas disponible. Y at-il des moyens simples pour convertir soit5M ou 5MB et similaires à des octets?

la solution de max était élégante, mais l'équivalent le plus court qui fonctionnerait dans mon cas est au minimum sed -e 's/b//i;s/k/*1000/i;s/m/*1000000/i;s/g/*1000000000/i;s/t/*1000000000000/i' | bc.

+1

http://www.linuxquestions.org/questions/programming-9/perl-vs-bash-code- number-of-lines-534142/ – Anders

+0

C'est la conversion dans le mauvais sens. – l0b0

+0

Il n'est pas vraiment difficile de le changer ... – Anders

Répondre

3

Quelque chose comme ça?

$ 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 
1

Edit:

Ma réponse originale est juste stupide. Voici une solution Bash pure basée sur 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)) 

C'est plus que mon uniligne d'origine qu'en vertu du fait qu'il comprend insensibilité à la casse alors que ce dernier n'a pas (bien qu'il puisse et la fonction a). Le nombre de caractères est deux fois plus long que le nombre maximum quand il est ajusté pour une fonctionnalité équivalente.

Original:

Voici une solution pure Bash:

En fonction (voir ci-dessous pour une seule ligne):

#!/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})) 
} 

Pour tester la fonction:

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 

Résultats:

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 

Comme promis, enfin, la version one-liner:

$ 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