Convert a String to a Number

I read in two numbers from a user but the number is a string.

#!/bin/bash
read -p "Enter first number: " num1
read -p "Enter second number: " num2

I know you can use the the "expr" or "bc" command to automatically convert the string to a number then add them together. But I don't want to add these numbers, I just want to convert the string to a number. That's it. How would I go about doing this? thank you

Hi Loc...

In shell scripting consider a number as a string of characters in _integer_ form only:-

Last login: Fri Mar 17 15:30:19 on ttys000
AMIGA:amiga~> number1="101"
AMIGA:amiga~> number2=57
AMIGA:amiga~> number3='8'
AMIGA:amiga~> echo "$(( number1 + number2 - number3 ))"
150
AMIGA:amiga~> _

If however you want to change the 'type' you will have to use something like python:-

Last login: Fri Mar 17 15:32:35 on ttys000
AMIGA:amiga~> python
Python 2.7.10 (default, Jul 30 2016, 19:40:32) 
[GCC 4.2.1 Compatible Apple LLVM 8.0.0 (clang-800.0.34)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> x="123"
>>> type(x)
<type 'str'>
>>> y=int(str(x))
>>> type(y)
<type 'int'>
>>> exit()
AMIGA:amiga~> _

In bash use the typeset builtin (declare builtin does the same ). You declare the variable, THEN assign value to it:

typeset -i var=19

Once a variable is declared as a number it no longer will interpreted as a string, and allows some arithmetic operations.
From Typing variables: declare or typeset

You need to be careful that you validate the input, else you can end up with this:-

$ typeset -i wally
$ wally=abc
$ echo $wally
0
$ wally=123abc456
bash: 123abc456: value too great for base (error token is "123abc456")
$

Perhaps you would be better to do something more like this after you read in num1 & num2:-

vnum1=$(tr -cd "[0-9]" < <(echo $num1))
if [ "$vnum1" != $"num1" ]
then
   echo "Invalid input!"
   exit
fi

It's a bit messy, but keeping it all as strings means that the shell doesn't care what the contents are. You can always for it to an integer afterwards should you wish.

I hope that this helps,
Robin

Another way, a bit more shell independent (as long as it is Posix):

$ num=0001
$ echo "$num"
0001
$ echo "$((num+=0))"
1
$ echo "$num"
1

FWIW: a slightly better approach than

typeset -i

is simply to validate input
Example, pure bash validation of a number using bash regex where the variable is named n:

regex="^([0-9]$"
if [[ $n =~ $regex ]] ; then
  echo "$n is numeric"
else
  echo "$n is not numeric"
fi

@jim, what if num=+1 or -001

@scrutinizer - you are correct. Look below.

Actually, my point was not about anything that uses validation. That whole thing was a trip down a rabbit hole.

The OP insisted that there was no way that a variable could be treated as "polymorphic", I showed two shell examples to the contrary. i.e., 01 and 1 would register as 1 in

 [ $myvar -eq 1 ]

The only conclusion was that OP was using an ancient shell, so I suggested typeset. Then we all went down a rabbit hole. :slight_smile: We are still there.

To answer your question in the OP's context let's see what ksh88 on Solaris 10 "thinks":

 for i in "-1" "+1" "01" "1" " 1"
 do
        
    printf "%%s=%s: %%d=:%d: " $i $i  
    [ $i -eq 1 ] && echo "Numeric and equals 1"
    [ $i -eq -1 ] && echo "Numeric and equals -1"
    [ $i -eq 0 ] && echo "probably not numeric"
 done

output:

%s=-1: %d=:-1: Numeric and equals -1
%s=+1: %d=:1: Numeric and equals 1
%s=01: %d=:1: Numeric and equals 1
%s=1: %d=:1: Numeric and equals 1
%s=1: %d=:1: Numeric and equals 1

Now let's compare that to bash and bash plus RE - note change to RE

#!/bin/bash
for i in "-1" "+1" "01" "1" " 1"  "-000001"
do
 printf "%%s=:%s: %%d=:%d: " $i $i  
 [ $i -eq 1 ] && echo "Numeric and equals 1"
 [ $i -eq -1 ] && echo "Numeric and equals -1"
 [ $i -eq 0 ] && echo "probably not numeric"
done

echo 'using RE'
regex='^([+-]{0,1}[0-9]+$| [0-9]+$|[0-9]+$)'

for i in "-1" "+1" "01" "1" " 1" "-0000001"
do
   printf "%%s=:%s: %%d=:%d: " $i $i  
   if [[ $i =~  $regex ]] ; then 
         echo 'tests numeric '  
   else
         echo 'tests not numeric'
   fi      
done

output:

%s=:-1: %d=:-1: Numeric and equals -1
%s=:+1: %d=:1: Numeric and equals 1
%s=:01: %d=:1: Numeric and equals 1
%s=:1: %d=:1: Numeric and equals 1
%s=:1: %d=:1: Numeric and equals 1
%s=:-000001: %d=:-1: Numeric and equals -1
using RE
%s=:-1: %d=:-1: tests numeric
%s=:+1: %d=:1: tests numeric
%s=:01: %d=:1: tests numeric
%s=:1: %d=:1: tests numeric
%s=:1: %d=:1: tests numeric
%s=:-0000001: %d=:-1: tests numeric

Hmm. ksh88 is the oldest shell I have. So none of the other stuff is really needed to do what the OP appears to have wanted, IMO. This was my original point. Your point is that signed numbers fail the RE in my example, which is true. My bad. Fixed.

All of this might have been over the OP's level of understanding anyway.

1 Like

Hi JM...

Now change the character '1' to a '9' and see what you get.

Apart from the fact that with the OP's example any ASCII character can be 'read' so can octal _numbers_, valid numeric characters but invalid _integer_ results.

Maybe we are looking too deep though.

To re-iterate my original question:

I get 2 numbers from a user and pass those 2 numbers to a function but it keeps on converting the numbers back to a string, so my function keeps crashing. If I was to hard code the numbers into the function then it works perfectly.

I tried this and it doesn't work

 
 read -p "Num 1: " num1
 read -p "Num 2: " num2
 myFunc $num1 $num2
 

I tried this and it doesn't work

 
 read -p "Num 1: " num1
 read -p "Num 2: " num2
  
 typeset -i num1
 typeset -i num2
  
 myFunc $num1 $num2
 

I even tried this and it doesn't work

myFunc $((num1+1-1)) $((num2+1-1))

But this work

myFunc 5 6 

Is there a way I can get the numbers to remain as an integer instead of changing to a string by default? Thank you

Works fine for me, NO string conversion :

myfunc() { echo $1, $2, $(($1 + $2)); }
myfunc $num1 $num2
23, 42, 65

Run your script incl. function with the -x (xtrace) option set and post the execution log.