Softpanorama
(slightly skeptical) Open Source Software Educational Society

May the source be with you, but remember the KISS principle ;-)

Softpanorama Search

Arithmetic Expressions in BASH

News

See also

Recommended  Links

 ((...)) command and let command Arrays Pipes in Loops 
Comparison operators Loops in Shell Advanced navigation Shell History Humor Etc

Older UNIX shells like Borne shell  have clumsy, extremely inconvenient and confusing way of doing arithmetic.  When Perl arrived, it was clear the shell is an outdated crap for most system administration tasks that involve substantial calculations. So ksh93 was created to fight back the lost ground. While it failed to stop Perl, ksh93 was a big improvement, and later bash re-implemented most of the advanced features of ksh93 plus a couple of its own.  The version to look for the features described is bash 3.2 or later.

First of all in BASH you can (and should) use $(( )) or let for integer arithmetic expressions. For example:

	i=$(( i + 1 ))
	let i+=1

or

	i=$(( i++))
	let i++

You must not have spaces around the equals sign, as with any bash variable assignment. As long as you keep to integer arithmetic, you can use all the standard C-language operators inside of $(()). Spaces are treated as in any normal algorithmic language: they are options.  But again, please be aware that space before equal sign confuses bash into thinking that this is a function invocation:

	i = $(( i + 5 )) # not what you think!

In this case bash will try to run a program named i and its first argument would be an equal sign, and its second argument would be the number you get adding 5 to the value of $i.

Another oddity to these expressions is that the R-value rule ($ should be prefixed to the shell variable on the right side of assignment statement to get its value) is not applicable inside the double parentheses. But at the same time you do need the dollar sign for positional parameters (e.g.,$2) to distinguish it from a numeric constant (e.g., "2"). Here's an example:

	i=$(( i + $2 ))

There is a several shortcuts supported by BASH. One is += type of operators (familiar to any programmer):

	let i=i+5

can be written as

	let i+=5
Usual C-style increments work too:
	let i++
or
	(( i++ ))
Explanation of assignment operators in bash
Operator Operation with assignment Use Meaning
= Simple assignment a=b a=b
*= Multiplication a*=b a=(a*b)
/= Division a/=b a=(a/b)
%= Remainder a%=b a=(a%b)
+= Addition a+=b a=(a+b)
-= Subtraction a-=b a=(a-b)
<<= Bit-shift left a<<=b a=(a<<b)
>>= Bit-shift right a>>=b a=(a>>b)
&= Bitwise "and" a&=b a=(a&b)
^= Bitwise "exclusive or" a^=b a=(a^b)
|= Bitwise "or" a|=b a=(a|b)
 

These assignment operators are also available with $(( )) provided they occur inside the double parentheses. The outermost assignment is still just plain old shell variable assignment.

The assignments can also be cascaded, through the use of the comma operator:

	echo $(( X+=2 , Y++ ))

which will do both assignments and then echo the result of the second expression (since the comma operator returns the value of its second expression).

Unlike many other places in bash scripts where certain characters have special meanings (like the asterisk for wildcard patterns or parentheses for subshell execution), in these expressions we don't need to use quotes or backslashes to escape them since they don't have their special meaning in let statements or inside of the $(( )) construct:

	let Y=(X+2)*10

	Y=$(( ( X + 2 ) * 10 ))

The $(( )) syntax allows all sorts of whitespace within the parentheses. For that reason, it is both less prone to errors and makes the code much more readable and is, therefore, our preferred way of doing bash integer arithmetic. However, an exception can be made for the occasional += assignment or ++ operator, or when we get nostalgic for the early days of BASIC programming (which had a LET statement).

The differences between the ((...)) command and let command

There are two major differences:

The ((...)) command is more convenient to use than let, because some of the arithmetic operators (like *) have special meaning to the shell.  The only contract that is often used with let is inrement like in

let i++

This commands is equivalent to:

let i=i+1 

and to

(( i=i + 1 ))
as well as to
(( i++ ))  
Before the Korn shell introduced let and (( ... )) commands, the only way to perform arithmetic was with expr. For example, to do the same increment X operation using expr:
X=`expr $X + 1` 

There is a similar mechanism for integer arithmetic with shell variables using the bash built-in let statement. It uses the same arithmetic operators as the $(( )) construct:

	let i=i+5 

When using let, there are some fancy assignment operators we can use such as this (which will accomplish the same thing as the previous line):

	let i+=5
The ((...)) command also can be used in any control statements. for example:
function mess
{
   if (( "$1" > 0 )) ; then>
      total=$1
   else
      total=100
   fi
   tail -$total /var/adm/messages | more
}

Using Array Variables

Initialization of arrays in bash has format similar to Perl:

	solaris=(serv01 serv02 serv07 ns1 ns2)

Each element of the array is a separate word in the list enclosed in parentheses. Then you can refer to each this way:

	echo solaris is installed on ${solaris[2]}

If you omit index writing  echo $solaris you will get the first element too.

Another example taken from Bash Shell Programming in Linux
array=(red green blue yellow magenta)
len=${#array[*]}
echo "The array has $len members. They are:"
i=0
while [ $i -lt $len ]; do
	echo "$i: ${array[$i]}"
	let i++
done                          
Run this example:

$ ./myscript.sh

The array has 5 members. They are:
0: red
1: green
2: blue
3: yellow
4: magenta


Old News ;-)

Please visit  Heiner Steven's SHELLdorado, the best shell scripting site on the Internet

[Jun 19, 2008] Bash Arrays  by Mitch Frazier

Linux Journal

If you're used to a "standard" *NIX shell you may not be familiar with bash's array feature. Although not as powerful as similar constructs in the P languages (Perl, Python, and PHP) and others, they are often quite useful.

Bash arrays have numbered indexes only, but they are sparse, ie you don't have to define all the indexes. An entire array can be assigned by enclosing the array items in parenthesis:

  arr=(Hello World)
Individual items can be assigned with the familiar array syntax (unless you're used to Basic or Fortran):
  arr[0]=Hello
  arr[1]=World
But it gets a bit ugly when you want to refer to an array item:
  echo ${arr[0]} ${arr[1]}
To quote from the man page:
The braces are required to avoid conflicts with pathname expansion.

 

In addition the following funky constructs are available:

  ${arr[*]}         # All of the items in the array
  ${!arr[*]}        # All of the indexes in the array
  ${#arr[*]}        # Number of items in the array
  ${#arr[0]}        # Length if item zero
The ${!arr[*]} is a relatively new addition to bash, it was not part of the original array implementation.

 

The following example shows some simple array usage (note the "[index]=value" assignment to assign a specific index):

#!/bin/bash

array=(one two three four [5]=five)

echo "Array size: ${#array[*]}"

echo "Array items:"
for item in ${array[*]}
do
    printf "   %s\n" $item
done

echo "Array indexes:"
for index in ${!array[*]}
do
    printf "   %d\n" $index
done

echo "Array items and indexes:"
for index in ${!array[*]}
do
    printf "%4d: %s\n" $index ${array[$index]}
done
Running it produces the following output:
Array size: 5
Array items:
   one
   two
   three
   four
   five
Array indexes:
   0
   1
   2
   3
   5
Array items and indexes:
   0: one
   1: two
   2: three
   3: four
   5: five

Note that the "@" sign can be used instead of the "*" in constructs such as ${arr[*]}, the result is the same except when expanding to the items of the array within a quoted string. In this case the behavior is the same as when expanding "$*" and "$@" within quoted strings: "${arr[*]}" returns all the items as a single word, whereas "${arr[@]}" returns each item as a separate word.

The following example shows how unquoted, quoted "*", and quoted "@" affect the expansion (particularly important when the array items themselves contain spaces):

#!/bin/bash

array=("first item" "second item" "third" "item")

echo "Number of items in original array: ${#array[*]}"
for ix in ${!array[*]}
do
    printf "   %s\n" "${array[$ix]}"
done
echo

arr=(${array[*]})
echo "After unquoted expansion: ${#arr[*]}"
for ix in ${!arr[*]}
do
    printf "   %s\n" "${arr[$ix]}"
done
echo

arr=("${array[*]}")
echo "After * quoted expansion: ${#arr[*]}"
for ix in ${!arr[*]}
do
    printf "   %s\n" "${arr[$ix]}"
done
echo

arr=("${array[@]}")
echo "After @ quoted expansion: ${#arr[*]}"
for ix in ${!arr[*]}
do
    printf "   %s\n" "${arr[$ix]}"
done
When run it outputs:
Number of items in original array: 4
   first item
   second item
   third
   item

After unquoted expansion: 6
   first
   item
   second
   item
   third
   item

After * quoted expansion: 1
   first item second item third item

After @ quoted expansion: 4
   first item
   second item
   third
   item

Mitch Frazier is the System Administrator at Linux Journal.

Arithmetic expansion with double parentheses, and using let 

The use of backticks (backquotes) in arithmetic expansion has been superseded by double parentheses -- ((...)) and $((...)) -- and also by the very convenient let construction.
z=$(($z+3))
z=$((z+3))                                  #  Also correct.
                                            #  Within double parentheses,
                                            #+ parameter dereferencing
                                            #+ is optional.

# $((EXPRESSION)) is arithmetic expansion.  #  Not to be confused with
                                            #+ command substitution.



# You may also use operations within double parentheses without assignment.

  n=0
  echo "n = $n"                             # n = 0

  (( n += 1 ))                              # Increment.
# (( $n += 1 )) is incorrect!
  echo "n = $n"                             # n = 1


let z=z+3
let "z += 3"  #  Quotes permit the use of spaces in variable assignment.
              #  The 'let' operator actually performs arithmetic evaluation,
              #+ rather than expansion.

 

Recommended Links


In case of broken links please try to use Google search. If you find the page please notify us about new location
Google     

Please visit  Heiner Steven SHELLdorado  the best shell scripting site on the Internet

Advanced Bash-Scripting Guide

Linux.com Turn Vim into a bash IDE

Debugging

Reference

Examples shipped with bash 3.2 and newer
Path Description X-ref
./bashdb Deprecated sample implementation of a bash debugger.  
./complete Shell completion code.  
./functions Example functions.  
./functions/array-stuff Various array functions (ashift, array_sort, reverse).  
./functions/array-to-string Convert an array to a string.  
./functions/autoload An almost ksh-compatible 'autoload' (no lazy load). ksh
./functions/autoload.v2 An almost ksh-compatible 'autoload' (no lazy load). ksh
./functions/autoload.v3 A more ksh-compatible 'autoload' (with lazy load). ksh
./functions/basename A replacement for basename(1). basename
./functions/basename2 Fast basename(1) and dirname(1) functions for bash/sh. basename, dirname
./functions/coproc.bash Start, control, and end co-processes.  
./functions/coshell.bash Control shell co-processes (see coprocess.bash).  
./functions/coshell.README README for coshell and coproc.  
./functions/csh-compat A C-shell compatibility package. csh
./functions/dirfuncs Directory manipulation functions from the book The Korn Shell.  
./functions/dirname A replacement for dirname(1). dirname
./functions/emptydir Find out if a directory is empty.  
./functions/exitstat Display the exit status of processes.  
./functions/external Like command, but forces the use of external command.  
./functions/fact Recursive factorial function.  
./functions/fstty Front-end to sync TERM changes to both stty(1) and readline 'bind'. stty.bash
./functions/func Print out definitions for functions named by arguments.  
./functions/gethtml Get a web page from a remote server (wget(1) in bash).  
./functions/getoptx.bash getopt function that parses long-named options.  
./functions/inetaddr Internet address conversion (inet2hex and hex2inet).  
./functions/inpath Return zero if the argument is in the path and executable. inpath
./functions/isnum.bash Test user input on numeric or character value.  
./functions/isnum2 Test user input on numeric values, with floating point.  
./functions/isvalidip Test user input for valid IP addresses.  
./functions/jdate.bash Julian date conversion.  
./functions/jj.bash Look for running jobs.  
./functions/keep Try to keep some programs in the foreground and running.  
./functions/ksh-cd ksh-like cd: cd [-LP] [dir[change]]. ksh
./functions/ksh-compat-test ksh-like arithmetic test replacements. ksh
./functions/kshenv Functions and aliases to provide the beginnings of a ksh environment for bash ksh
./functions/login Replace the login and newgrp built-ins in old Bourne shells.  
./functions/lowercase Rename files to lowercase. rename lower
./functions/manpage Find and print a manpage. fman
./functions/mhfold Print MH folders, useful only because folders(1) doesn't print mod date/times.  
./functions/notify.bash Notify when jobs change status.  
./functions/pathfuncs Path related functions (no_path, add_path, pre-path, del_path). path
./functions/README README  
./functions/recurse Recursive directory traverser.  
./functions/repeat2 A clone of the C shell built-in repeat. repeat, csh
./functions/repeat3 A clone of the C shell built-in repeat. repeat, csh
./functions/seq Generate a sequence from m to n;m defaults to 1.  
./functions/seq2 Generate a sequence from m to n;m defaults to 1.  
./functions/shcat Readline-based pager. cat, readline pager
./functions/shcat2 Readline-based pagers. cat, readline pager
./functions/sort-pos-params Sort the positional parameters.  
./functions/substr A function to emulate the ancient ksh built-in. ksh
./functions/substr2 A function to emulate the ancient ksh built-in. ksh
./functions/term A shell function to set the terminal type interactively or not.  
./functions/whatis An implementation of the 10th Edition Unix sh built-in whatis(1) command.  
./functions/whence An almost ksh-compatible whence(1) command.  
./functions/which An emulation of which(1) as it appears in FreeBSD.  
./functions/xalias.bash Convert csh alias commands to bash functions. csh, aliasconv
./functions/xfind.bash A find(1) clone.  
./loadables/ Example loadable replacements.  
./loadables/basename.c Return nondirectory portion of pathname. basename
./loadables/cat.c cat(1) replacement with no options—the way cat was intended. cat, readline pager
./loadables/cut.c cut(1) replacement.  
./loadables/dirname.c Return directory portion of pathname. dirname
./loadables/finfo.c Print file info.  
./loadables/getconf.c POSIX.2 getconf utility.
./loadables/getconf.h Replacement definitions for ones the system doesn't provide.  
./loadables/head.c Copy first part of files.  
./loadables/hello.c Obligatory "Hello World" / sample loadable.  
./loadables/id.c POSIX.2 user identity.  
./loadables/ln.c Make links.  
./loadables/logname.c Print login name of current user.  
./loadables/Makefile.in Simple makefile for the sample loadable built-ins.  
./loadables/mkdir.c Make directories.  
./loadables/necho.c echo without options or argument interpretation.  
./loadables/pathchk.c Check pathnames for validity and portability.  
./loadables/print.c Loadable ksh-93 style print built-in.  
./loadables/printenv.c Minimal built-in clone of BSD printenv(1).  
./loadables/push.c Anyone remember TOPS-20?  
./loadables/README README  
./loadables/realpath.c Canonicalize pathnames, resolving symlinks.  
./loadables/rmdir.c Remove directory.  
./loadables/sleep.c Sleep for fractions of a second.  
./loadables/strftime.c Loadable built-in interface to strftime(3).  
./loadables/sync.c Sync the disks by forcing pending filesystem writes to complete.  
./loadables/tee.c Duplicate standard input.  
./loadables/template.c Example template for loadable built-in.  
./loadables/truefalse.c True and false built-ins.  
./loadables/tty.c Return terminal name.  
./loadables/uname.c Print system information.  
./loadables/unlink.c Remove a directory entry.  
./loadables/whoami.c Print out username of current user.  
./loadables/perl/ Illustrates how to build a Perl interpreter into bash.  
./misc Miscellaneous  
./misc/aliasconv.bash Convert csh aliases to bash aliases and functions. csh, xalias
./misc/aliasconv.sh Convert csh aliases to bash aliases and functions. csh, xalias
./misc/cshtobash Convert csh aliases, environment variables, and variables to bash equivalents. csh, xalias
./misc/README README  
./misc/suncmd.termcap SunView TERMCAP string.  
./obashdb Modified version of the Korn Shell debugger from Bill Rosenblatt's Learning the Korn Shell.
./scripts.noah Noah Friedman's collection of scripts (updated to bash v2 syntax by Chet Ramey).  
./scripts.noah/aref.bash Pseudo-arrays and substring indexing examples.  
./scripts.noah/bash.sub.bash Library functions used by require.bash.  
./scripts.noah/bash_version. bash A function to slice up $BASH_VERSION.  
./scripts.noah/meta.bash Enable and disable eight-bit readline input.  
./scripts.noah/mktmp.bash Make a temporary file with a unique name.  
./scripts.noah/number.bash A fun hack to translate numerals into English.  
./scripts.noah/PERMISSION Permissions to use the scripts in this directory.  
./scripts.noah/prompt.bash A way to set PS1 to some predefined strings.  
./scripts.noah/README README  
./scripts.noah/remap_keys.bash A front end to bind to redo readline bindings. readline
./scripts.noah/require.bash Lisp-like require/provide library functions for bash.  
./scripts.noah/send_mail. Replacement SMTP client written in bash.  
./scripts.noah/shcat.bash bash replacement for cat(1). cat
./scripts.noah/source.bash Replacement for source that uses current directory.  
./scripts.noah/string.bash The string(3) functions at the shell level.  
./scripts.noah/stty.bash Front-end to stty(1) that changes readline bindings too. fstty
./scripts.noah/y_or_n_p.bash Prompt for a yes/no/quit answer. ask
./scripts.v2 John DuBois' ksh script collection (converted to bash v2 syntax by Chet Ramey).  
./scripts.v2/arc2tarz Convert an arc archive to a compressed tar archive.  
./scripts.v2/bashrand Random number generator with upper and lower bounds and optional seed. random
./scripts.v2/cal2day.bash Convert a day number to a name.  
./scripts.v2/cdhist.bash cd replacement with a directory stack added.  
./scripts.v2/corename Tell what produced a core file.  
./scripts.v2/fman Fast man(1) replacement. manpage
./scripts.v2/frcp Copy files using ftp(1) but with rcp-type command-line syntax.  
./scripts.v2/lowercase Change filenames to lowercase. rename lower
./scripts.v2/ncp A nicer front end for cp(1) (has -i, etc)..  
./scripts.v2/newext Change the extension of a group of files. rename
./scripts.v2/nmv A nicer front end for mv(1) (has -i, etc).. rename
./scripts.v2/pages Print specified pages from files.  
./scripts.v2/PERMISSION Permissions to use the scripts in this directory.  
./scripts.v2/pf A pager front end that handles compressed files.  
./scripts.v2/pmtop Poor man's top(1) for SunOS 4.x and BSD/OS.  
./scripts.v2/README README  
./scripts.v2/ren Rename files by changing parts of filenames that match a pattern. rename
./scripts.v2/rename Change the names of files that match a pattern. rename
./scripts.v2/repeat Execute a command multiple times. repeat
./scripts.v2/shprof Line profiler for bash scripts.  
./scripts.v2/untar Unarchive a (possibly compressed) tarfile into a directory.  
./scripts.v2/uudec Carefully uudecode(1) multiple files.  
./scripts.v2/uuenc uuencode(1) multiple files.  
./scripts.v2/vtree Print a visual display of a directory tree. tree
./scripts.v2/where Show where commands that match a pattern are.  
./scripts Example scripts.  
./scripts/adventure.sh Text adventure game in bash!  
./scripts/bcsh.sh Bourne shell's C shell emulator. csh
./scripts/cat.sh Readline-based pager. cat, readline pager
./scripts/center Center a group of lines.  
./scripts/dd-ex.sh Line editor using only /bin/sh, /bin/dd, and /bin/rm.  
./scripts/fixfiles.bash Recurse a tree and fix files containing various bad characters.  
./scripts/hanoi.bash The inevitable Towers of Hanoi in bash.  
./scripts/inpath Search $PATH for a file the same name as $1; return TRUE if found. inpath
./scripts/krand.bash Produces a random number within integer limits. random
./scripts/line-input.bash Line input routine for GNU Bourne Again Shell plus terminal-control primitives.  
./scripts/nohup.bash bash version of nohup command.  
./scripts/precedence Test relative precedences for && and || operators.  
./scripts/randomcard.bash Print a random card from a card deck. random
./scripts/README README  
./scripts/scrollbar Display scrolling text.  
./scripts/scrollbar2 Display scrolling text.  
./scripts/self-repro A self-reproducing script (careful!).  
./scripts/showperm.bash Convert ls(1) symbolic permissions into octal mode.  
./scripts/shprompt Display a prompt and get an answer satisfying certain criteria. ask
./scripts/spin.bash Display a spinning wheel to show progress.  
./scripts/timeout Give rsh(1) a shorter timeout.  
./scripts/vtree2 Display a tree printout of the direcotry with disk use in 1k blocks. tree
./scripts/vtree3 Display a graphical tree printout of dir. tree
./scripts/vtree3a Display a graphical tree printout of dir. tree
./scripts/websrv.sh A web server in bash!  
./scripts/xterm_title Print the contents of the xterm title bar.  
./scripts/zprintf Emulate printf (obsolete since printf is now a bash built-in).  
./startup-files Example startup files.  
./startup-files/Bash_aliases Some useful aliases (written by Fox).  
./startup-files/Bash_profile Sample startup file for bash login shells (written by Fox).  
./startup-files/bash-profile Sample startup file for bash login shells (written by Ramey).  
./startup-files/bashrc Sample Bourne Again Shell init file (written by Ramey).  
./startup-files/Bashrc.bfox Sample Bourne Again Shell init file (written by Fox).  
./startup-files/README README  
./startup-files/apple Example startup files for Mac OS X.  
./startup-files/apple/aliases Sample aliases for Mac OS X.  
./startup-files/apple/bash.defaults Sample User preferences file.  
./startup-files/apple/environment Sample Bourne Again Shell environment file.  
./startup-files/apple/login Sample login wrapper.  
./startup-files/apple/logout Sample logout wrapper.  
./startup-files/apple/rc Sample Bourne Again Shell config file.  
./startup-files/apple/README README


Copyright © 1996-2009 by Dr. Nikolai Bezroukov. www.softpanorama.org was created as a service to the UN Sustainable Development Networking Programme (SDNP) in the author free time. Submit comments This document is an industrial compilation designed and created exclusively for educational use and is placed under the copyright of the Open Content License(OPL). Site uses AdSense so you need to be aware of Google privacy policy. Original materials copyright belong to respective owners. Quotes are made for educational purposes only in compliance with the fair use doctrine.

Disclaimer:

Last modified: August 22, 2009