I need to convert human-readable sizes into bytes. Unfortunately numfmt function is not accessible for me. Is there any other alternative? I need a shell/bash function to call from inside the sh script.

1K should be converted to 1000, 1M to 1000 000 etc.


If Perl is available:

echo your_string | perl -ne '
    BEGIN{ %suffixes=( K => 3, M => 6, G => 9, T => 12, P => 15, E => 18 ); 
           $suffix_regex = join "|", keys %suffixes;
    printf "%d\n", $_;

Since this is to be used as a text filter, it's more appropriate to define it as a perl script and pipe input into it. You can embed it inside a shell function by adding the following to your .bashrc (assuming you use Bash):

myconvert() {
    cat <<'EOF' >/dev/null
#!--perl-- -n
BEGIN{ %suffixes=( K => 3, M => 6, G => 9, T => 12, P => 15, E => 18 ); 
       $suffix_regex = join "|", keys %suffixes;
printf "%d\n", $_;
   exec perl -x "/path/to/your/.bashrc"

A solution using sed and bc:

  sed '
  ' </dev/stdin | bc | sed 's/\..*$//' # Final sed to remove decimal point

Usage (the same for both solutions):

$ echo '5.23K' | myconvert
$ echo '6.27G' | myconvert

This solution assumes your input consists only of strings of the form 5.23K (fractional part optional), otherwise, bc won't know what to do with them.


The Perl one-liner could have been inserted as-is into a shell function with < /dev/stdin as with the sed solution. This didn't cross my mind when writing the first version of the answer. I'm leaving the perl -x trick up there in case it can benefit someone else, though.

  • I need a shell function. I tried for 5.1M and result is 5.1000000 where decimal point is not somewhat expected. Is it possible to wrap it into function with parameter? – jaksky Feb 13 '14 at 12:10
  • @jaksky See if the edit helps. – Joseph R. Feb 13 '14 at 12:35
  • Sorry I really need a shell/bash function. I cannot use perl. Sorry for that. – jaksky Feb 13 '14 at 12:47
  • @jaksky Does that exclude other tools like sed and awk as well? You need a solution that relies only on shell builtins? – Joseph R. Feb 13 '14 at 12:54
  • @ Joseph - no. awk, sed etc. are ok. I found numfmt function but that isn't unfortunatelly available. Ideal use case would be to call that function to convert. e.g. toBytes 5.23K would yield 5230. All is done on one line as those values are parsed from some text. – jaksky Feb 13 '14 at 13:15

With gawk, you could do:

convert() {
  gawk --use-lc-numeric -v RS='[KMGTPE]' '
    match($0, /[0-9]*['"$(locale decimal_point)"']?[0-9]+$/) {
      $0 = substr($0, 1, RSTART-1) sprintf("%'\''.17g", \
        substr($0,RSTART) * (10**(index(RS,RT)*3-3)))
    }{printf "%s", $0 RT}'


$ echo "You owe me £1.23M" | convert
You owe me £1,230,000
$ export LC_ALL=fr_FR.UTF-8
$ echo "Tu me dois 1,34M€" | convert
Tu me dois 1 340 000€
$ echo "Sie schulden mir 1,34M€" | LC_ALL=de_DE.UTF-8 convert
Sie schulden mir 1.340.000€

If you don't have to worry about decimal or thousand separators (your question is not clear on that as you used a French style thousand separator there), and use . as the decimal separator and no thousand separator, you could do:

convert() {
  perl -pe 's/\d*\.?\d+([KMGTPE])/$&*10**(index(KMGTPE,$1)*3+3)/ge'

If you'd rather 112334E be displayed as 112334000000000000000000 instead of 1.12334e+23, you can add the -Mbignum option to perl above.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.