Bash declare integer

Why declare integers? As you know, bash is not like most programming languages. One thing that makes it different is its type system; Unlike static and dynamic typed languages, it allows you to switch type-specific behaviors on/off through variable attributes. Hence, you would declare an integer in bash to make the variable behave more like an integer.

Previously in bash using declare, we covered all the uses for the bash builtin command declare or typeset. Here we focus on the usage for specifying integer variables in bash. For sake of simplicity we will use declare instead of typeset.

Declaring integer variables in bash

As they say, All is string in bash. However, if we hope to escape from characters and strings to use numbers, we may opt to restrict a variable to storing integers like 1 and -1. And in the case that the integer does not know what to do with the value it is being assigned, assign it to 0. To accomplish this in bash, we turn on the integer attribute for the variable using builtins declare builtin combined with -i. Makes sense, right? We can also use local or export in place of declare if we needed.

Follows are examples of int variable assignment in action.

Example: Assigning int value without quotes

Assigning an int value without double-quotes would as expected assign a variable the numeric value of the unquoted string. That is, if the unquoted string equals 1, the variable would be assigned the value 1.

_() {
  local -i int
  ## assign int value without quotes
  int=1
  cecho green "int=1"
  cecho yellow "${int}" # 1
}
_

Example: Assigning int value with quotes

In the last example we assigned int the value of 1 as you would expect, without using quotes. It turns out that quotes do not affect assignment of integer variables in bash if the symbol on the right hand side begins with a digit. You will see later that this is not the case when the right hand side could be a variable name.

_() {
  local -i int
  ## assign int value with quotes
  int="2"
  cecho green "int=2"
  cecho yellow "${int}" # 2
}
_

Example: Assigning int value a string matching a variable name

In the last two examples, we were doing the right thing, actually assigning an int variable a numberical value. What happens if we try to assign it the string two. You may be surprised what you find.

_() {
  local var
  local -i int
  ## assign int value of another variable
  int=var
  cecho green "int=var"
  cecho yellow "${int}" # 0
}
_

Example: Assigning int variable name with side effects

In the last examples, we assigned in the name of a varaible and saw what happened. Now let's introduce side effects.

_() {
  local var
  local -i int
  ## assign int value of another variable with side effects
  var=0
  cecho green "int=var"
  int=var
  cecho yellow "${int}" # 0
  cecho green "(( var++ ))"
  (( var++ ))
  cecho green "int=var"
  int=var
  cecho yellow "${int}" # 1
}
_

Example: The rest of int variable assignment

It may take some time to split this variable assignment example script into few enough bytes to be easily processed by the reader. Until then, here is the rest of int variable assignment examples.

_() {
  local var
  local empty_var
  local -i int
  ## assign int value of another variable w/ increment
  int=var+1
  cecho green "int=var+1"
  cecho yellow "${int}" # 4
  ## assign int value of another variable empty 
  int=empty_var
  cecho green "int=\"empty_var\""
  cecho yellow "${int}" # 0
  ## assign int value of another variable in quotes
  int="var"
  cecho green "int=\"var\""
  cecho yellow "${int}" # 3
  ## assign int value of another variable random
  int="RANDOM"
  cecho green "int=\"RANDOM\""
  cecho yellow "int: ${int}" # maybe 1234
}
_

Example: Putting int variable assignment all together

Here is the demo script left so that you may see what examples above look like in the whole context of the script. Feel free to skip through as needed.

_() {
  local var
  local empty_var
  local -i int
  ## assign int value without quote
  int=1
  cecho green "int=1"
  cecho yellow "${int}" # 1
  ## assign int value with quote
  int="2"
  cecho green "int=2"
  cecho yellow "${int}" # 2
  ## assign int value of another variable
  int=var
  cecho green "int=var"
  cecho yellow "${int}" # 0
  ## assign other variable value to int
  var=3
  cecho green "var=3"
  ## assign int value of another variable again
  int=var
  cecho green "int=var"
  cecho yellow "${int}" # 3
  ## assign int value of another variable w/ increment
  int=var+1
  cecho green "int=var+1"
  cecho yellow "${int}" # 4
  ## assign int value of another variable empty 
  int=empty_var
  cecho green "int=\"empty_var\""
  cecho yellow "${int}" # 0
  ## assign int value of another variable in quotes
  int="var"
  cecho green "int=\"var\""
  cecho yellow "${int}" # 3
  ## assign int value of another variable random
  int="RANDOM"
  cecho green "int=\"RANDOM\""
  cecho yellow "int: ${int}" # maybe 1234
}
_

Source: 210513-run-example-001-bash-declare-intenger-assignment.sh

Here is what you would expect to see if you were to run the script as bashboy.

$ bashboy run:example-001-bash-declare-intenger-assignment
int=1 
1 
int=2 
2 
int=var 
0 
var=3 
int=var 
3 
int=var+1 
4 
int="empty_var" 
0 
int="var" 
3 
int="RANDOM" 
int: 12839 

As you see there are some quirks to keep in mind when using the integer attibute in bash, especially in the case when assigning an alphanumeric string not begining with zero matching an existing variable name to an integer variable. However, it is possibly to prevent undefined behavior from occurring by paying attention to scope.

Usage

Let's skip to the good part, creating integer variables!
Here is how to declare an integer variable in bash. Note that int is not a keyword for integer. That is the job of the -i option to the builtin declare.

  • determine if a variable is an integer *
  • create an integer variable *

determine if a variable is an integer

There is more than one way to determine if a variable is an integer or not but you could get away with checking if the variable has the -i attribute. After all, an integer variable holds integer values despite what you try to assign to it.

# check if a variable is an integer
declare -p int			# declare -i int="1"

We say a variable is an integer if the -i attribute set, i.e. if declare -p returns either -i or -ir. Note that in the case that the variable is found to have the -n attribute set, testing the end nameref is required to determine if the variable is an integer.

create an integer variable

# create an integer variable and modify through assignment
unset one			# just to be sure
declare -i int		# int is an integer
int=5				# int=$(( 5 ))=5
int+=1 				# int=$(( int + 1 ))=6
int+=int+1 			# int=$(( int + int + 1 ))=13
int=one				# int=$(( one ))=

Now look at what happens without the integer attribute.

# result of assignment without integer attribute
unset int			# just to be sure
unset one			# just to be sure
int=5				# int=5
int+=1 				# int=${int}1=51
int+=int+1 			# int=${int}+int+1=51int+1
int=one				# int=one

Now you see what happens if you forget to declare a variable as an integer. Not something that you want running loose in your program.

breakdown

declare -i int

We say that if there is a variable named int, it now has the integer attribute set. If the variable named in the declare command is not set yet, then the attribute is applied to a future variable unless unset. Using local instead of declare, causes the attribute to only be applied in subsequent assignments in the local scope.

int=5

Depending on whether the variable has the integer attribute this sets the value of int to the string 5 or arithmetic expansion of 5. In the case of 5, the result yields 5 for both cases.

int+=1

Should increment int if integer attribute set.

int+=int+1

Should double int and increment if integer attribute set.

Definitions

Definition of types of integer variables.

  • Integer variable
  • Read-only integer variable
  • Pure integer variable

integer variable

A variable with the -i attribute set.

We define an integer variable in bash as a variable with the integer attribute set. The question we ask here is, "Is it valid to declare a variable with the integer attribute in combination with another attribute?" This may be expanded later.

read-only integer variable

An integer variable with the -r attribute set.

pure integer variable

A variable with only the -i attribute set.

We define a pure integer variable in bash as a variable with only the integer attribute set.

Motivation

You may be wondering why you would even bother declaring integer variables in bash. After all, aren't all variable strings? Yes exactly, but using declare to add the integer attribute to a variable affects assignment.

Why declare integers in bash?

To better understand how and why integers are declared in bash, it is helpful to look at behavior with and without using integer variables.

#!/bin/bash
## test-bash-declare-integer-1
## - fun with integers attributes
## version 0.0.1 - initial
##################################################
test-bash-declare-integer-1() {
  ## setup
  local lonely_integer		# one int is fine
  local i			# for ease of use
  declare -n i=lonely_integer 	# declare attributes
  ## (1) do something wrong with integers
  i=asdf			# (1) asdf as i is asdf
  echo ${i}			# (2) asdf
  ## (2) what if we give it the integer attribute?
  declare -i lonely_integer	# (1) declare integer
  i=asdf			# (2) asdf as i is 0
  echo ${i}			# (3) 0
  ## (3) what happened?
  declare +i lonely_integer	# (1) revert back
  i=$(( ${asdf} ))		# (2) what happens in (2) under (1) conditions
  echo ${i}			# (3) 0
  ## (4) proof: part i (without integer attribute)
  asdf=1			# assignment for proof
  i=$(( ${asdf} ))		# same as (3.2)
  echo ${i}			# 1
  ## (5) proof: part ii (with integer attribute)
  declare -i lonely_integer	# same as (2.1)
  i=asdf			#  asdf as i is 1
  echo ${i}			# 1
}
##################################################
if [ ${#} -eq 0 ] 
then
 true
else
 exit 1 # wrong args
fi
##################################################
test-bash-declare-integer-1
##################################################
## generated by create-stub2.sh v0.1.1
## on Sun, 03 Feb 2019 17:36:53 +0900
## see <https://github.com/temptemp3/sh2>
##################################################

You see that adding the integer attribute forces arithmetic expressions to be evaluated on assignment.

Questions

Here are a few quesrtions related to declaring integers in bash.

how do I compare two integers?

Arithmetic binary operators can be used to compare integers in bash in the form arg1 OP arg2. For example, we may test if two integers are not equal as follows.

test ! ${a} -eq ${b} # a != b

If the variable a and b are attributed with the integer attribute, then nothing unexpected should happen. However, if a or b are not attributed with the integer attribute, then an error may occur as follows.

a="c d"
b="e"
test ${a} -eq ${b} #
#bash: test: too many arguments
echo ${?} # 2
set -v -x 
test ${a} -eq ${b} #
#+ test a d -eq c 
#bash: test: too many arguments

how do I declare an integer bash?

Declare integer variables using the declare builtin with the -i option.

declare -i myint

how do I declare a local integer in bash?

Declare integer variables with local bindings using declare in conjunction with the local (1). In the shortest form, the operation may be performed in a single statement (2) consisting of local, the integer attribute option -i, and variable name.

(1), separate local binding and integer attribute assignment

local myint
declare -i myint

or (2), local binding with integer attribute set

local -i myint

Either way works.

© Nicholas Shellabarger