0

I'm trying to sort out a bash command to convert a number from base 10 to an arbitrary base, using a specified set of characters (for example, to base 26 using letters a-z, although that's not actually my use-case).

I have solved this problem before, but not in bash (which I have limited experience in), and not in quite some time.

Any ideas?

5
  • 2
    Easier if you use zsh: unix.stackexchange.com/a/616227/70524 Commented Jun 27, 2023 at 13:48
  • @muru zsh is unfortunately not an option. Commented Jun 27, 2023 at 14:39
  • Please edit your question and show an examples with input and expected output. Showing your solution in a different language might also help. You could solve this with bc or (GNU) dc. Example conversion of number 1234567890 to base 26 assuming a = value 0, b = 1 etc. echo 26 o 1234567890 p | dc | awk '{ for(i=1; i<=NF; i++) printf("%c",$i+97) } END { printf("\n") }' Commented Jun 27, 2023 at 15:11
  • This is one of those things that would be more sanely done in pretty much any other programming language; the shell languages are mostly about running commands and really aren't made for general-purpose number-crunching or data mangling. (though Bash does support the conversion in the other direction out of the box, using prefixes like 12# for base 12 in front of the numbers. E.g. echo $(( 12#100 )) $(( 12#bb )) prints 144 143. Not that it helps much.) Commented Jun 27, 2023 at 15:25
  • Related: BASH base conversion from decimal to hex Commented Jun 27, 2023 at 16:38

3 Answers 3

3

I had something similar lying around, so I polished it up a bit for you

#!/bin/bash
#
# usage: convert_base <number-to-convert> <output-base> <output-digit-string>
#
# example:
#   $ convert_base 3735928559 16 "0 1 2 3 4 5 6 7 8 9 A B C D E F"
#   DEADBEEF

decimal_number=$1
output_base=$2
read -ra output_digits <<< "$3"

# TODO various assertions

if ((decimal_number == 0)); then
    output=${output_digits[0]}
else
    while ((decimal_number > 0)); do
        digit=$(( decimal_number % output_base ))
        output="${output_digits[digit]}$output"
        decimal_number=$(( decimal_number / output_base ))
    done
fi

printf '%s\n' "$output"
2

base 2-64 to decimal - just use built-in BASH $(( base#number ))

> echo $(( 36#B002RD3KCS ))
1117165531505356
> echo $(( 16#FF ))
255

revert conversion could be done with standard bc + helper function:

# base10 to base2..base52
# Usage: decimal_to_anybase <OtputBase> <DecimalNum>
function decimal_to_anybase()
{
   BASE52=($(echo {0..9} {A..Z} {a..z}));   # array of 'base_digits'
   base="$1";                               # output base 2..52
   arg="$2";                                # source decimal
   res=$(bc <<< "obase=$base; $arg")
   if [ "$base" -le 16 ]; then              # bases 2..16 returned as is 
       echo "$res"
   else                                     # bases 17..52 returned as array indexes
      for i in $res; do 
          echo -n ${BASE52[$(( 10#$i ))]}   # output BASE52[base_digit]
      done && echo
   fi 
}

> decimal_to_anybase 36 1117165531505356
B002RD3KCS
0

Maybe stating the obvious, but bash's printf builtin can do base 8 and 16:

$ printf '%o\n' 1234
2322
$ printf '%#o\n' 1234
02322
$ printf '%x\n' 1234
4d2
$ printf '%#x\n' 1234
0x4d2
$ printf '%X\n' 1234
4D2
$ printf '%#X\n' 1234
0X4D2

Even hexadecimal floats:

$ LC_ALL=C printf '%a\n' 1234.56
0x9.a51eb851eb851ecp+7
$ LC_ALL=C printf '%A\n' 1234.56
0X9.A51EB851EB851ECP+7

(here using LC_ALL=C to make sure the decimal radix character is .)

But it doesn't do other bases for which you'd need more advanced shells such as zsh or ksh93 or do it by hand.

To store the result in a variable:

printf -v oct %o 1234

is more efficient than:

oct=$(printf %o 1234)

Which in bash (contrary to ksh93 or the sh of some BSDs) means forking a process and send the result through a pipe.

For those who're not stuck with bash, some alternatives with some other shells can be found at:

You must log in to answer this question.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.