LinuxQuestions.org

LinuxQuestions.org (/questions/)
-   Linux - General (https://www.linuxquestions.org/questions/linux-general-1/)
-   -   Nice script to convert numbers between bases (bin/dec/oct/hex) (https://www.linuxquestions.org/questions/linux-general-1/nice-script-to-convert-numbers-between-bases-bin-dec-oct-hex-704884/)

hgate73 02-15-2009 04:38 PM

Nice script to convert numbers between bases (bin/dec/oct/hex)
 
I had to write this script for an assignment, and it took me hours of pulling out my hair to figure it out (I'm new to shell scripting), so I thought I'd post it. I know it's probably not the most efficient way to do it, since a CASE would probably be better, but it works for me. :rolleyes:

Basically it converts numbers of one base (I.E. hex numbers like 2F) to another base (I.E. binary or decimal or octal).

Let me know if you like it, or if there's a way to improve it.

Code:

#!/bin/bash
# Title:        bConvert.sh
# Purpose:      Converts numbers from one base to another
# Requiremetns: BASH shell
# Author:      hgate73 (linuxquestions.org)

# Structure:
# $1 is base of number being converted (-d, -h, -b, -o)
# $2 is number to convert
# $3 is base of number to convert to  (-d, -h, -b, -o)
# Example: ./bConvert.sh -d 3 -b   will convert the decimal (-d for DECIMAL) number 3 to binary (-b for BINARY). It should result in 11

# This is to make sure the input value is in upper-case if it is a letter
number=$( echo "$2" | tr -s '[:lower:]' '[:upper:]' )

# Error checking
if [ $# = 0 ]; then echo "You didn't specify any arguments."; exit; fi

##################
# 1. Set IN type #
##################
if [ "$1" = "-b" ]; then    #bin/2
    inType='2'
elif [ "$1" = "-o" ]; then    #oct/8
    inType=8 
elif [ "$1" = "-d" ]; then    #dec/10
    inType=10
elif [ "$1" = "-h" ]; then    #hex/16
    inType=16
fi

###################
# 2. Set OUT type #
###################
if [ "$3" = "-b" ]; then    #bin/2
    outType='2'
elif [ "$3" = "-o" ]; then    #oct/8
    outType=8 
elif [ "$3" = "-d" ]; then    #dec/10
    outType='10'
elif [ "$3" = "-h" ]; then    #hex/16
    outType=16
fi

#########################
# 3. Perform conversion #
#########################
result=$(echo "obase=$outType;ibase=$inType;$number" | bc); echo $result


i92guboj 02-15-2009 05:43 PM

This is the way I'd do it:

Code:

#!/bin/bash

function die () {
  echo "$1"
  exit 1
  # it's better to exit with an error code other than zero,
  # this way, external programs can know whether this succeeded
  # or not :)
}
 
function convert() {
  number=$( echo "$3" | tr -s '[:lower:]' '[:upper:]' )
  result=$(echo "obase=$2;ibase=$1;$number" | bc)
  if [ ! "$?" == "0" ]; then
    die "bc error: wrong values."
  fi
  echo "Original number in base $1: $number"
  echo "Converted number in base $2: $result"
}
 
# Error checking
if [ $# = 0 ]; then die "You didn't specify any arguments."; fi

# Defaults
inType=10
outType=16

while [ -n "$1" ]; do
  case "$1" in
    -i|--input-base)
      if [ -n "$2" ]; then
        inType="$2"
      else
        die "  $1 requires an aditional parameter."
      fi
      shift; shift;
      ;;
    -o|--output-base)
      if [ -n "$2" ]; then
        outType="$2"
      else
        die "  $1 requires an aditional parameter."
      fi
      shift; shift;
      ;;
    *)
      convert $inType $outType $1
      shift;
      ;;
  esac
done

Case along with shift let you handle the arguments in a smarter and more flexible way (you can use -i and -o on any order, as long as the following argument is the base). Note that it will also convert as many numbers as desired on a single run:

Code:

bconvert -o 3 108762345243 42352453 524352453
Original number in base 10: 108762345243
Converted number in base 3: 101101201211112121020000
Original number in base 10: 42352453
Converted number in base 3: 2221200201122101
Original number in base 10: 524352453
Converted number in base 3: 1100112122212100020

It's better to use different argument names for different arguments. Your original design is prone to confusion in that regard because the arguments to determine inType and outType are named the same. This script should handle any base, and not just 8, 10 and 16. It also has defaults for inType and outType so you don't forcingly have to specify none.

What could be enhanced? Well, the error handling could be better. Also you could add a -h|--help clause in the case statement. The help text could be designed as a function (you already have two examples in that code), a function that should be called either when you use -h or --help or when you invoke the program without arguments. Designing it as a function let's you call it from many places without having to duplicate the code. You could as well add -idec, -ihex, -ibin, -ioct, -ooct, -odec, -ohex, -obin parameters that would be shorthands for these common bases.

This is a quick adaptation so it might have some flaws that I haven't yet considered.

EDIT: fixed.

hgate73 02-16-2009 03:38 PM

This is good information, thanks a lot. I knew there had to be a way to do it with CASE statements, but I haven't covered them yet and I don't know how to use them. Thanks for the great example.

H_TeXMeX_H 02-17-2009 03:19 AM

Sorry, but I'd do this in C not bash.

nx5000 02-17-2009 03:51 AM

Another way
Code:

#!/usr/bin/perl
#This program is freeware, after 15 days, you have to purchase it ;-)
print unpack("$ARGV[2]*",pack("$ARGV[0]*",$ARGV[1])) . "\n"

./script C 3 B
00000011

./script B 00001111 H
0f

floats to native ieee representation:

./script f 1.1 H
cdcc8c3f


All times are GMT -5. The time now is 04:00 PM.