Bash numerical base conversion

Bash numerical base conversion

am 14.07.2006 23:50:47 von Dave Farrance

While writing a script to display the character set, I wondered what
numerical base conversion could be done in bash. Converting to base-10
is easy enough, e.g "echo $((8#1234))", but can you convert to another
base with bash?

I can use "bc", but repeatedly loading it inside a loop slows things
right down. Is there a more elegant way?

for (( j=32; j<256; j++ )); do # loop through char set
q=$(echo "obase=8; $j" | bc) # convert to octal
(( j % 16 == 0 )) && echo -ne "\n$q " # octal line address
echo -ne "\\$q " # display 8-bit character
done
echo

--
Dave Farrance

Re: Bash numerical base conversion

am 15.07.2006 00:36:11 von cfajohnson

On 2006-07-14, Dave Farrance wrote:
> While writing a script to display the character set, I wondered what
> numerical base conversion could be done in bash. Converting to base-10
> is easy enough, e.g "echo $((8#1234))", but can you convert to another
> base with bash?
>
> I can use "bc", but repeatedly loading it inside a loop slows things
> right down. Is there a more elegant way?
>
> for (( j=32; j<256; j++ )); do # loop through char set
> q=$(echo "obase=8; $j" | bc) # convert to octal
> (( j % 16 == 0 )) && echo -ne "\n$q " # octal line address
> echo -ne "\\$q " # display 8-bit character
> done
> echo

_d2b() { ## USAGE: d2b [-[bB]BASE] num
BASE=2 ## default
BCHARS=0123456789
UBASE='0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ'
LBASE='0123456789abcdefghijklmnopqrstuvwxyz'

case "$1" in
-b) BCHARS=$LBASE
BASE=$2
shift 2;;
-B) BCHARS=$UBASE
BASE=$2
shift 2
;;
-b*) BCHARS=$LBASE
BASE=${1#??}
shift
;;
-B*) BCHARS=$UBASE
BASE=${1#??}
shift
;;
-[2-9]*) BCHARS=$UBASE
BASE=${1#?}
shift
;;
-*) return 5 ;;
esac

if [ $BASE -eq 10 ]
then
_D2B=$1
return
elif [ $BASE -gt ${#BCHARS} ]
then
echo "Maximum base is ${#BCHARS}" >&2
return 1
fi

unset __D2B

_D2B=
num=$1
while [ $num -ne 0 ]
do
rem=$(( $num % $BASE ))
if [ $BASE -gt 10 ]
then
_substr "$BCHARS" $(( $rem + 1 )) 1
_D2B=$_SUBSTR$_D2B
else
_D2B=$rem$_D2B
fi
num=$(( $num / $BASE ))
done
}

d2b()
{
_d2b "$@" && printf "%s\n" "$_D2B"
}

--
Chris F.A. Johnson, author
Shell Scripting Recipes: A Problem-Solution Approach (2005, Apress)
===== My code in this post, if any, assumes the POSIX locale
===== and is released under the GNU General Public Licence

Re: Bash numerical base conversion

am 15.07.2006 00:58:25 von William Park

Dave Farrance wrote:
> While writing a script to display the character set, I wondered what
> numerical base conversion could be done in bash. Converting to base-10
> is easy enough, e.g "echo $((8#1234))", but can you convert to another
> base with bash?
>
> I can use "bc", but repeatedly loading it inside a loop slows things
> right down. Is there a more elegant way?
> ...

For 8 and 16, you can use 'printf' (builtin or system command). For
others, you can use my 'binary' builtin,
http://home.eol.ca/~parkw/index.html#binary

--
William Park , Toronto, Canada
ThinFlash: Linux thin-client on USB key (flash) drive
http://home.eol.ca/~parkw/thinflash.html
BashDiff: Super Bash shell
http://freshmeat.net/projects/bashdiff/

Re: Bash numerical base conversion

am 15.07.2006 01:22:42 von Dave Farrance

"Chris F.A. Johnson" wrote:

[ base conversion script snipped ]

>d2b()
>{
> _d2b "$@" && printf "%s\n" "$_D2B"
>}

That's neat.

But heck, I forgot that printf was in bash as a builtin - and, of
course, that can do hex and octal conversions. Works like a flash now.

for (( j=32; j<256; j++ )); do # loop through char set
(( j % 16 == 0 )) && printf "\n%04x " $j # hex line address
echo -ne "\\$(printf "%03o" $j) " # display character
done
echo

Here's the unicode version of the character set display. Works in
konsole (with a few oddities), but probably not much else.

echo -ne "\e%G" # Select unicode
for (( j=32; j<65536; j++ )); do # full 16-bit loop
(( j % 16 == 0 )) && printf "\n%04x " $j # hex line address
q=$(printf "%06o" $j) # number to octal
echo -ne "\3$((40+${q:0:2}))\2${q:2:2}\2${q:4:2} " # parse as unicode
done
echo -e "\e%@" # Normal charset

--
Dave Farrance

Re: Bash numerical base conversion

am 15.07.2006 11:40:58 von John L

"Dave Farrance" wrote in message news:a59gb2tln6n4oeju5ku7dom2fehh42nplr@4ax.com...
>
> But heck, I forgot that printf was in bash as a builtin - and, of
> course, that can do hex and octal conversions. Works like a flash now.
>
> for (( j=32; j<256; j++ )); do # loop through char set
> (( j % 16 == 0 )) && printf "\n%04x " $j # hex line address
> echo -ne "\\$(printf "%03o" $j) " # display character
> done
> echo
>

How fast is a flash though?

On my elderly linux box, the fast version was only around a second
faster than the slow original.

Here is the fast version using printf

$ cat 1baseconv
for (( j=32; j<256; j++ )); do # loop through char set
(( j % 16 == 0 )) && printf "\n%04x " $j # hex line address
echo -ne "\\$(printf "%03o" $j) " # display character
done
echo

$ time bash 1baseconv > /dev/null

real 0m0.382s
user 0m0.119s
sys 0m0.226s

And here is the slow version using bc

$ cat 2baseconv
for (( j=32; j<256; j++ )); do # loop through char set
q=$(echo "obase=8; $j" | bc) # convert to octal
(( j % 16 == 0 )) && echo -ne "\n$q " # octal line address
echo -ne "\\$q " # display 8-bit character
done
echo

$ time bash 2baseconv > /dev/null

real 0m1.258s
user 0m0.313s
sys 0m0.909s

The reason for redirecting the output to /dev/null is to facilitate
comparison with simply reading the manual pages. (Output to the
terminal added less than half a second in each case.)

$ time man ascii > /dev/null

real 0m0.344s
user 0m0.181s
sys 0m0.125s

$ time man iso_8859-1 > /dev/null

real 0m0.381s
user 0m0.213s
sys 0m0.135s

Another fast method would be to use the slow script once
to output to a file which can then be turned into a local
man page (which saves writing a man page for the script itself
which can then be thrown away) or simply cat-ed.

Writing the whole thing as a bc (or dc) script is left as an exercise
for the reader.

--
John.

Re: Bash numerical base conversion

am 15.07.2006 12:11:56 von Dave Farrance

"John L" wrote:

>On my elderly linux box, the fast version was only around a second
>faster than the slow original.

>Here is the fast version using printf

> real 0m0.382s
> user 0m0.119s
> sys 0m0.226s
>
>And here is the slow version using bc

> real 0m1.258s
> user 0m0.313s
> sys 0m0.909s

On my laptop, using bash 3.00, I get a sixfold speed increase:

Fast version: real 0.06 user 0.02 sys 0.03
Slow version: real 0.38 user 0.16 sys 0.20

Maybe your shell version doesn't have printf builtin? Or maybe you've
got a power saving scheme set very conservatively so that you get a slow
start.

--
Dave Farrance