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

Contents Bulletin Scripting in shell and Perl Network troubleshooting History Humor

if statements in shell

News

Bash

Recommended Links

Reference Short-circuit if statements Examples Additional examples
Checking the exit status of a command Test: Obsolete construct for testing Files and Strings Short circuit operators && and || Double square bracket conditions String comparisons Numeric Conditionals File Attribute Checking
Sequences of commands Arithmetic expressions Shell Conditional Operators Caveats BASH Debugging Shell history Humor Etc

Introduction

Note: Those are my old lecture notes for FDU students. They use copyrighted examples from several sources such as Advanced Bash-Scripting Guide and as such can be used for educational purposes only in accordance with fair use doctrine.

The simplest type of flow control construct is the conditional, embodied in the shell if statement, which using Algol-68 syntax and actually is the only survivor of Algol-68 syntax among currently used languages.

You use a conditional when you want to choose whether or not to do something, or to choose among a small number of things to do, according to the truth or falsehood of conditions. Conditions test values of shell variables, characteristics of files, whether or not commands run successfully, and other factors. The shell has a large set of built-in tests that are relevant to the task of shell programming.

The if construct has the following syntax:

if condition
then
    statements
[elif condition
    then statements...]
[else
    statements]
fi
The elif or else parts can be omitted.

Examples of condition (see Arithmetic expressions and Comparison operators for more information):

    [[ $user = 'nick' ]]  # string comparison condition 
    [[ $user != 'root' ]] # string comparison condition
    (( uid == 0 ))
    (( uid > 1000 ))
    (( ( $uid > 10 ) && ( $uid < 100 ) )) # arithmetic condition

There are five forms of an IF statement in shell

  1. If statement which checks the exit status of a command
  2. test: Testing Files and Strings (If statements that evaluates conditional expression using test)
  3. Short circuit if statements ( Conditional Execution && and ||). See also Short-circuit if statements
  4. Double square bracket condition test
  5. If statement with double round parenthesis conditionals (Numeric Conditionals)
  6. Conditionals with File Attribute Checking

Checking the exit status of a command

Every UNIX command returns an integer code to its parent. This return code is called the exit status. 0 is usually the "OK" exit status, while anything else (1 to 255) usually denotes an error.

The simplest form (without the elif and else parts, a.k.a. clauses) executes the statements only if the exit code is true (in shell unlike Perl this mean code equal zero). For example:

if cd /fake; then echo "cd returned OK"; fi

If you add an else clause, you get the ability to execute one set of statements if a condition is true or another set of statements if the condition is false. If the status is 0, the condition evaluates to true; if it is anything else, the condition is considered false. The same is true for each condition attached to an elif statement (if any).

You can use as many elif (a contraction of "else if") clauses as you wish; they introduce more conditions, and thus more choices for which set of statements to execute. If you use one or more elifs, you can think of the else clause as the "if all else fails" part.

This enables us to write code of the form:

if command ran successfully
then   
    normal processing
else
    error processing
fi
For example:
if cd /fake;  
then echo "cd returned OK"; fi  
else echo "cd failed"; 
fi

test: Obsolete construct for Testing Files and Strings

Historically conditional expressions in Unix shells were introduced via test command. For instance, test can check whether a file is writable before your script tries to write to it. It can treat the string in a shell variable as a number and do comparisons ("Is that number less than 1000?"). You can combine tests, too ("If the file exists and it's readable and the message number is more than 500..."). Some versions of test have more tests than others.

The test command returns a zero status if the test was true and a nonzero status otherwise, so people usually use test with if , while, or until. Here's a way your program could check to see if the user has a readable file named .profile in the home directory:

if test -r $HOME/.profile
then
    echo "$myname: You already have .profile file and its readable"
else
    echo " you do not have .profile file. Copying ..."
    cp /etc/skel/.profile $HOME/.profile
    exit 1
fi

The test command also lets you test for something that isn't true. Add an exclamation point (!) before the condition you're testing. For example, the following test is true if the .profile file is not readable:

if test ! -r $HOME/.profile 
... ... ...

The hack that was implemented is to link text to the file named [. Yes, that's a left bracket. It was a pretty interesting hack: you can use it interchangeably with the test command with one exception: there has to be a matching right bracket (]) at the end of the test. The second example above could be rewritten this way:

if [ ! -r $HOME/.profile ]
then
    echo "$myname: Can't read your '.profile'.  You need to create one and make it readable." 1>&2
    exit 1
fi

Be sure to leave space between the brackets and other text. There are a couple of other common gotchas caused by empty arguments because shell attempts macro expansion before syntax analysis.

Short circuit operators && and ||

BASH allows you to combine exit statuses logically, so that you can test more than one thing at a time:

In both cases it's useful to think about them as "short-circuit and" and "short-circuit or," respectively:

In if statement consists of two conditions (which in turn can be statements ;-) connected by && like in following example

if condition1 && condition2
then
    ...
fi

condition1 is always executed and the result is used to decide if condition 2 should be evaluated. If and only if the first statement returns a return code 0 conditions2 is evaluated (executed). The then clause will be executed only if both succeeded.

In case of short-circuit or the situation is similar:

if statement1 || statement2
then
    ...
fi

statement1 is always executed. If it returns code zero (success), then statement2 will not be executed. Otherwise statement2 will be executed and its return code will be used for the deciding whether to execute then clause of the if statement or else clause. In other words then clause runs either statement1 or statement2 returns a zero code.

true && echo "Yes."
Yes.

true || echo "No."
No

false || echo "Yes."
Yes.

Note: These constructs can be used outside if statement as well. They provide an elegant way to implement if statement with only else clause.

Let's assume that we need to write a script that checks a /etc/passwd file for the presence of two users who left the company. We can use grep for this: it returns exit status 0 if it found the given string in its input, non-0 if not:

user=$1
if grep $user /etc/passwd || -e $home/$user
then
    print "user $user is not fully removed from the server."
fi

Double square bracket conditions

The [[ ]] construct was introduced in ksh88 as a way to compensate for multiple shortcomings and limitations of the [ ] (test) solution. Essentially it makes [ ] construct obsolete except for running a program to get a return code.

The [[ ]] construct expects expression. What is important delimiters [[ and ]] serve as single quotes so you do not have macro expansion inside: variable substitution and wildcard expansion aren't done within [[ and ]], making quoting less necessary.

One of the [[ ]] construct warts is that it redefined == as a pattern matching operation, which anybody who programmed in C/C++/Java strongly resent. Latest bash version corrected that and allow using Perl-style =~ operator instead (I think ksh93 allow that too):

string="abba"
[[ $string =∼ [aeiou] ]]
echo $?
0

[[ $string =∼ h[sdfghjkl] ]]
echo $?
1

Like [ ] construct [[ ]] construct can be used as a separate statement that returns an exit status depending upon whether condition is true or not. With && and || constructs discussed above this provides an alternative syntax for if-then and if-else constructs

if [[ -d $HOME/$user ]] ; then echo " Home for user $user exists..."; fi

can be written simpler as

[[ -d $HOME/$user ]] && echo " Home 
	for user $user exists..." 

There are several types of expressions that can be used inside [[ ... ]] construct:

String comparisons

Notes:

Operator True if...
str = pat[5]
str == pat[5]

str matches pat.

Note:  that's not what you logically expect, if you have some experience with C /C++/Java programming !!!

str != pat str does not match pat.
str1 < str2 str1 is less than str2 is collation order used
str1 > str2 str1 is greater than str2.
-n str str is not null (has length greater than 0).
-z str str is null (has length 0).
file1 -ef file2 file1 is another name for file2 (hard or symbolic link)

While we're cleaning up code we wrote in the last chapter, let's fix up the error handling in the highest script The code for that script is:

filename=${1:?"filename missing."}
howmany=${2:-10}
sort -nr $filename | head -$howmany

Recall that if you omit the first argument (the filename), the shell prints the message highest: 1: filename missing. We can make this better by substituting a more standard "usage" message:

if [[ -z $1 ]]; then
    print 'usage: howmany filename [-N]'
else
    filename=$1
    howmany=${2:-10}
    sort -nr $filename | head -$howmany
fi

It is considered better programming style to enclose all of the code in the if-then-else, but such code can get confusing if you are writing a long script in which you need to check for errors and bail out at several points along the way. Therefore, a more usual style for shell programming is this:

if [[ -z $1 ]]; then
    print 'usage: howmany filename [-N]'
    return 1
fi
filename=$1
howmany=${2:-10}
sort -nr $filename | head -$howmany

Numeric Conditionals

Most modern shells implements special construct for numeric conditions called ((...)) construct. See Arithmetic Expressions in BASH. For example

function mess
{
   if (( "$1" > 0 )) ; then
      total=$1
   else
      total=100
   fi
   tail -$total /var/adm/messages | more
}

The shell also provides a older set of arithmetic tests. These are different from character string comparisons like < and >, which compare lexicographic values of strings, not numeric values. For example, "6" is greater than "57" lexicographically, just as "p" is greater than "ox,"

Note: numeric comparisons in double square brackets are obsolete. You should use (( ... )) construct.

Arithmetic Test Operators

Test Comparison
-lt Less than
-le Less than or equal
-eq Equal
-ge Greater than or equal
-gt Greater than
-ne Not equal

You'll find these to be of the most use in the context of the integer variables we'll see in the next chapter. They're necessary if you want to combine integer tests with other types of tests within the same conditional expression.

However, the shell has a separate syntax for conditional expressions that involve integers only. It's considerably more efficient, so you should use it in preference to the arithmetic test operators listed above. Again, we'll cover the shell's integer conditionals in the next chapter.

File Attribute Checking

The other kind of operator that can be used in conditional expressions checks a file for certain properties. There are approximately two dozens of such operators. Most common are listed below; the rest refer to arcana like sticky bits, sockets, and file descriptors, and thus are of interest only to systems programmers and/or hackers.

Note: ksh88 and Posix shell does not support -e (file exist). For compatibility you can use -f if this is a file

Operator True if...
-a file file exists
-d file file is a directory
-f file file is a regular file (i.e., not a directory or other special type of file)
-r file You have read permission on file
-s file file exists and is not empty
-w file You have write permission on file
-x file You have execute permission on file, or directory search permission if it is a directory
-O file You own file
-G file Your group ID is the same as that of file
file1 -nt file2 file1 is newer than file2
file1 -ot file2 file1 is older than file2

Before we get to an example, you should know that conditional expressions inside [[ and ]] can also be combined using the logical operators && and ||, just as we saw with plain shell commands above, in the section entitled "Combinations of Exit Statuses."

It's also possible to combine shell commands with conditional expressions using logical operators, like this:

if command && [[ condition ]]; then ...

Note: You can also negate the truth value of a conditional expression by preceding it with an exclamation point (!), so that ! expr evaluates to true only if expr is false.

if [[ ! -d "/root" ]]; then
   print -n "The directory /root does not exist on the server "
fi

Furthermore, you can make complex logical expressions of conditional operators by grouping them with parentheses. construct (statement list) runs the statement list in a subshell, whose exit status is that of the last statement in the list, It can also be used outside if statement.

Now let's write a script that prints essentially the same information as ls -l but in a more user-friendly way. It provides an excellent illustration of many file operations used:

function fileinfo
{
if [[ ! -a $1 ]]; then
    print "file $1 does not exist."
    return 1 # nothing to do
fi
if [[ -d $1 ]]; then
    print -n "$1 is a directory that you may "
    if [[ ! -x $1 ]]; then
        print -n "not "
    fi
    print "search."
elif [[ -f $1 ]]; then
    print "$1 is a regular file."
else
    print "$1 is a special file."
fi
if [[ -O $1 ]]; then
    print 'you own the file.'
else
    print 'you do not own the file.'
fi
if [[ -r $1 ]]; then
    print 'you have read permission on the file.'
fi
if [[ -w $1 ]]; then
    print 'you have write permission on the file.'
fi
if [[ -x $1 && ! -d $1 ]]; then
    print 'you have execute permission on the file.'
fi
return 0
}

Here's how this function works:

Examples

The if/then construct tests whether a condition is true, and if so, executes one or more commands. Note that in this context, 0 (zero) will evaluate as true, as will a random string of alphanumeric. Puzzling out the logic of this is left as an exercise for the reader.

Example 1: An interesting usage of ability to execute statements in if construct:

if grep "can't find" <(nslookup sandbox.firma.com) ; then
   echo "DNS enty for sandbox.firma.com does not exists"
fi

Example 2: (adapted from Example 3-9Advanced Bash-Scripting Guide)

What is truth?

   #!/bin/bash
   if [ 0 ] #zero
      then
        echo "0 is true."
      else
        echo "0 is false."
   fi
 
   if [ ]  #NULL (empty condition)
   then
        echo "NULL is true."
   else
      echo "NULL is false."
   fi

   if [ "xyz" ] #string
   then
         echo "Random string is true."
   else
     echo "Random string is false."
   fi

   if [ $xyz ]  # uninitialized variable
   then
      echo "Uninitialized variable is true."
   else
      echo "Uninitialized variable is false."
   fi
 
   exit 0

Additional examples
from Advanced Bash-Scripting Guide

Example 3-10. Equivalence of [ ] and test

   1 #!/bin/bash
   2
   3 echo
   4
   5
   6 if test -z $1
   7 then
   8   echo "No command-line arguments."
   9 else
  10   echo "First command-line argument is $1."
  11 fi
  12
  13 # Both code blocks are functionally identical.
  14
  15 if [ -z $1 ]
  16 # if [ -z $1
  17 # also works, but outputs an error message.
  18 then
  19   echo "No command-line arguments."
  20 else
  21   echo "First command-line argument is $1."
  22 fi
  23
  24
  25 echo
  26
  27 exit 0

Example 3-11. Tests, command chaining, redirection

   1 #!/bin/bash
   2
   3 # This line is a comment.
   4
   5 filename=sys.log
   6
   7 if [ ! -f $filename ]
   8 then
   9   touch $filename; echo "Creating file."
  10 else
  11   cat /dev/null > $filename; echo "Cleaning out file."
  12 fi
  13
  14 # Of course, /var/log/messages must have
  15 # world read permission (644) for this to work.
  16 tail /var/log/messages > $filename
  17 echo "$filename contains tail end of system log."
  18
  19 exit 0

Example 3-12. arithmetic and string comparisons

   1 #!/bin/bash
   2
   3 a=4
   4 b=5
   5
   6 # Here a and b can be treated either as integers or strings.
   7 # There is some blurring between the arithmetic and integer comparisons.
   8 # Be careful.
   9
  10 if [ $a -ne $b ]
  11 then
  12   echo "$a is not equal to $b"
  13   echo "(arithmetic comparison)"
  14 fi
  15
  16 echo
  17
  18 if [ $a != $b ]
  19 then
  20   echo "$a is not equal to $b."
  21   echo "(string comparison)"
  22 fi
  23
  24 echo
  25
  26 exit 0

Example 3-13. testing whether a string is null

   1 #!/bin/bash
   2
   3 # If a string has not been initialized, it has no defined value.
   4 # This state is called "null" (not the same as zero).
   5
   6
   7 if [ -n $string1 ]   # $string1 has not been declared or initialized.
   8 then
   9   echo "String \"string1\" is not null."
  10 else
  11   echo "String \"string1\" is null."
  12 fi
  13 # Wrong result.
  14 # Shows $string1 as not null, although it was not initialized.
  15
  16 echo
  17
  18 # Lets try it again.
  19
  20 if [ -n "$string1" ]  # This time, $string1 is quoted.
  21 then
  22   echo "String \"string1\" is not null."
  23 else
  24   echo "String \"string1\" is null."
  25 fi
  26
  27 echo
  28
  29 if [ $string1 ]  # This time, $string1 stands naked.
  30 then
  31   echo "String \"string1\" is not null."
  32 else
  33   echo "String \"string1\" is null."
  34 fi
  35 # This works fine.
  36 # The [ ] test operator alone detects whether the string is null.
  37
  38 echo
  39
  40 string1=initialized
  41
  42 if [ $string1 ]  # This time, $string1 stands naked.
  43 then
  44   echo "String \"string1\" is not null."
  45 else
  46   echo "String \"string1\" is null."
  47 fi
  48 # Again, gives correct result.
  49
  50
  51 exit 0
  52
  53 # Thanks to Florian Wisser for pointing this out.

Example 3-14. zmost

   1 #!/bin/bash
   2
   3 #View gzipped files with 'most'
   4
   5 NOARGS=1
   6
   7 if [ $# = 0 ]
   8 # same effect as:  if [ -z $1 ]
   9 then
  10   echo "Usage: `basename $0` filename" >&2
  11   # Error message to stderr.
  12   exit $NOARGS
  13   # Returns 1 as exit status of script
  14   # (error code)
  15 fi
  16
  17 filename=$1
  18
  19 if [ ! -f $filename ]
  20 then
  21   echo "File $filename not found!" >&2
  22   # Error message to stderr.
  23   exit 2
  24 fi
  25
  26 if [ ${filename##*.} != "gz" ]
  27 # Using bracket in variable substitution.
  28 then
  29   echo "File $1 is not a gzipped file!"
  30   exit 3
  31 fi
  32
  33 zcat $1 | most
  34
  35 exit 0
  36
  37 # Uses the file viewer 'most'
  38 # (similar to 'less')

Recommended Links

Softpanorama hot topic of the month

Softpanorama Recommended

Reference

compound comparison

-a
logical and

exp1 -a exp2 returns true if both exp1 and exp2 are true.

-o
logical or

exp1 -o exp2 returns true if either exp1 or exp2 are true.

These are simpler forms of the comparison operators && and ||, which require brackets to separate the target expressions.

Extended Set of File Test Operators (Bash only)

In bash we have extended set of file test operators:

-e
file exists
-f
file is a regular file
-s
file is not zero size
-d
file is a directory
-b
file is a block device (floppy, cdrom, etc.)
-c
file is a character device (keyboard, modem, sound card, etc.)
-p
file is a pipe
-L
file is a symbolic link
-S
file is a socket
-r
file is readable (has read permission)
-w
file has write permission
-x
file has execute permission
-g
group-id flag set on file
-u
user-id flag set on file
-k
"sticky bit" set (if user does not own a directory that has the sticky bit set, she cannot delete files in it, not even files she owns)
-O
you are owner of file
-G
group-id of file same as yours
-t n
file descriptor n is open

This usually refers to stdin, stdout, and stderr (file descriptors 0 - 2).

f1 -nt f2
file f1 is newer than f2
f1 -ot f2
file f1 is older than f2
f1 -ef f2
files f1 and f2 are links to the same file
!
"not" -- reverses the sense of the tests above (returns true if condition absent).

Comparison operators (binary)

integer comparison

-eq
is equal to ($a -eq $b)
-ne
is not equal to ($a -ne $b)
-gt
is greater than ($a -gt $b)
-ge
is greater than or equal to ($a -ge $b)
-lt
is less than ($a -lt $b)
-le
is less than or equal to ($a -le $b)

string comparison

=
is equal to ($a = $b)
!=
is not equal to ($a != $b)
\<
is less than, in ASCII alphabetical order ($a \< $b)

Note that the "<" needs to be escaped.

\>
is greater than, in ASCII alphabetical order ($a \> $b)

Note that the ">" needs to be escaped.

See Example 3-91 for an application of this comparison operator.

-z
string is "null", that is, has zero length
-n
string is not "null".
This test requires that the string be quoted within the test brackets. You may use ! -z instead, or even just the string itself, without a test operator (see Example 3-13).

Top updates

Softpanorama Switchboard
Softpanorama Search


NEWS CONTENTS

Old News ;-)

[Nov 04, 2016] Coding Style rear-rear Wiki

Reading rear sources is an interesting exercise. It really demonstrates attempt to use "reasonable' style of shell programming and you can learn a lot.
Nov 04, 2016 | github.com

Relax-and-Recover is written in Bash (at least bash version 3 is needed), a language that can be used in many styles. We want to make it easier for everybody to understand the Relax-and-Recover code and subsequently to contribute fixes and enhancements.

Here is a collection of coding hints that should help to get a more consistent code base.

Don't be afraid to contribute to Relax-and-Recover even if your contribution does not fully match all this coding hints. Currently large parts of the Relax-and-Recover code are not yet in compliance with this coding hints. This is an ongoing step by step process. Nevertheless try to understand the idea behind this coding hints so that you know how to break them properly (i.e. "learn the rules so you know how to break them properly").

The overall idea behind this coding hints is:

Make yourself understood

Make yourself understood to enable others to fix and enhance your code properly as needed.

From this overall idea the following coding hints are derived.

For the fun of it an extreme example what coding style should be avoided:

#!/bin/bash for i in `seq 1 2 $((2*$1-1))`;do echo $((j+=i));done



   

Try to find out what that code is about - it does a useful thing.

Code must be easy to read Code should be easy to understand

Do not only tell what the code does (i.e. the implementation details) but also explain what the intent behind is (i.e. why ) to make the code maintainable.

Here the initial example so that one can understand what it is about:

#!/bin/bash # output the first N square numbers # by summing up the first N odd numbers 1 3 ... 2*N-1 # where each nth partial sum is the nth square number # see https://en.wikipedia.org/wiki/Square_number#Properties # this way it is a little bit faster for big N compared to # calculating each square number on its own via multiplication N=$1 if ! [[ $N =~ ^[0-9]+$ ]] ; then echo "Input must be non-negative integer." 1>&2 exit 1 fi square_number=0 for odd_number in $( seq 1 2 $(( 2 * N - 1 )) ) ; do (( square_number += odd_number )) && echo $square_number done

Now the intent behind is clear and now others can easily decide if that code is really the best way to do it and easily improve it if needed.

Try to care about possible errors

By default bash proceeds with the next command when something failed. Do not let your code blindly proceed in case of errors because that could make it hard to find the root cause of a failure when it errors out somewhere later at an unrelated place with a weird error message which could lead to false fixes that cure only a particular symptom but not the root cause.

Maintain Backward Compatibility

Implement adaptions and enhancements in a backward compatible way so that your changes do not cause regressions for others.

Dirty hacks welcome

When there are special issues on particular systems it is more important that the Relax-and-Recover code works than having nice looking clean code that sometimes fails. In such special cases any dirty hacks that intend to make it work everywhere are welcome. But for dirty hacks the above listed coding hints become mandatory rules:

For example a dirty hack like the following is perfectly acceptable:

# FIXME: Dirty hack to make it work # on "FUBAR Linux version 666" # where COMMAND sometimes inexplicably fails # but always works after at most 3 attempts # see http://example.org/issue12345 # Retries should have no bad effect on other systems # where the first run of COMMAND works. COMMAND || COMMAND || COMMAND || Error "COMMAND failed."

Character Encoding

Use only traditional (7-bit) ASCII charactes. In particular do not use UTF-8 encoded multi-byte characters.

Text Layout Variables Functions Relax-and-Recover functions

Use the available Relax-and-Recover functions when possible instead of re-implementing basic functionality again and again. The Relax-and-Recover functions are implemented in various lib/*-functions.sh files .

test, [, [[, (( Paired parenthesis See also

[May 02, 2015] ArithmeticExpression

2014-02-13 | Greg's Wiki

Arithmetic in BASH is integer math only. You can't do floating point math in Bash; if you need that capability, see Bash FAQ #22.

Also see the Bash hackers article about the full syntax theory. /!\ The $[ ] syntax is deprecated

There are several ways to tell Bash to treat numbers as integers instead of strings, and to do basic arithmetic operations on them. The first is to use the let command:

let a=17+23
echo "a = $a"      # Prints a = 40

Note that each arithmetic expression has to be passed as a single argument to the let command, so you need quotes if there are spaces or globbing characters, thus:

let a=17 + 23      # WRONG
let a="17 + 23"    # Right
let 'a = 17 + 23'  # Right
let a=17 a+=23     # Right (2 arithmetic expressions)

let a[1]=1+1       # Wrong (try after touch a1=1+1 or with shopt -s failglob)
let 'a[1]=1+1'     # Right
let a\[1]=1+1      # Right

Division in Bash is integer division, and it truncates the results, just as in C:

let a=28/6
echo "a = $a"      # Prints a = 4

In addition to the let command, one may use the (( )) syntax to enforce an arithmetic context. If there is a $ (dollar sign) before the parentheses, then a substitution is performed (more on this below). White space is allowed inside (( )) with much greater leniency than with let, and variables inside (( )) don't require $ (because string literals aren't allowed). Examples:

((a=$a+7))         # Add 7 to a
((a = a + 7))      # Add 7 to a.  Identical to the previous command.
((a += 7))         # Add 7 to a.  Identical to the previous command.

((a = RANDOM % 10 + 1))     # Choose a random number from 1 to 10.
                            # % is modulus, as in C.

# (( )) may also be used as a command.  > or < inside (( )) means
# greater/less than, not output/input redirection.
if ((a > 5)); then echo "a is more than 5"; fi

(( )) without the leading $ is not a standard sh feature. It comes from ksh and is only available in ksh, Bash and zsh. $(( )) substitution is allowed in the POSIX shell. As one would expect, the result of the arithmetic expression inside the $(( )) is substituted into the original command. Like for parameter substitution, arithmetic substitution is subject to word splitting so should be quoted to prevent it when in list contexts. Here are some examples of the use of the arithmetic substitution syntax:

a=$((a+7))         # POSIX-compatible version of previous code.
if test "$((a%4))" = 0; then ...
lvcreate -L "$((4*1096))" -n lvname vgname   # Actual HP-UX example.

Variables may be declared as integers so that any subsequent assignments to them will always assume a numeric context. Essentially any variable that's declared as an integer acts as if you had a let command in front of it when you assign to it. For example:

unset b             # Forget any previous declarations
b=7+5; echo "$b"    # Prints 7+5
declare -i b        # Declare b as an integer
b=7+5; echo "$b"    # Prints 12

Also, array indices are a numeric context:

n=0
while read line; do
   array[n++]=$line      # array[] forces a numeric context
done

There is one common pitfall with arithmetic expressions in Bash: numbers with leading zeroes are treated as octal. For example,

# Suppose today is September 19th.
month=$(date +%m)
next_month=$(( (month == 12) ? 1 : month+1 ))
# bash: 09: value too great for base (error token is "09")

This causes great confusion among people who are extracting zero-padded numbers from various sources (although dates are by far the most common) and then doing math on them without sanitizing them first. (It's especially bad if you write a program like this in March, test it, roll it out... and then it doesn't blow up until August 1.)

If you have leading-zero problems with Bash's built-in arithmetic, there are two possible solutions. The first is, obviously, to remove the leading zeroes from the numbers before doing math with them. This is not trivial in Bash, unfortunately, because Bash has no ability to perform substitutions on a variable using regular expressions (it can only do it with "glob" patterns). But you could use a loop:

# This removes leading zeroes from a, one at a time.
while [[ $a = 0* ]]; do a=${a#0}; done

You can do the above without using a loop, by using extended globs; see FAQ #67 for more information. Or, you could use sed; that may be more efficient if you're reading many numbers from a stream, and can arrange to sanitize them all in one command, rather than one by one.

Without a loop:

# This removes leading zeroes from a, all at once.
a=${a##+(0)}

The third solution is to force Bash to treat all numbers as base 10 by prefixing them with 10#. This might be more efficient, but also may be less elegant to read.

a=008
let b=a+1       # Generates an error because 008 is not valid in octal.
let b=10#$a+1   # Force a to be treated as base 10.  Note: the $ is required.

Finally, a note on the exit status of commands, and the notions of "true" and "false", is in order. When bash runs a command, that command will return an exit status from 0 to 255. 0 is considered "success" (which is "true" when used in the context of an if or while command). However, in an arithmetic context, there are places where the C language rules (0 is false, anything else is true) apply.

Some examples:

true; echo "$?"       # Writes 0, because a successful command returns 0.
((10 > 6)); echo "$?" # Also 0.  An arithmetic command returns 0 for true.
echo "$((10 > 6))"    # Writes 1.  An arithmetic expression returns 1 for true.

In addition to a comparison returning 1 for true, an arithmetic expression that evaluates to a non-zero value is also true in the sense of a command.

if ((1)); then echo true; fi     # Writes true.

This also lets you use "flag" variables, just like in a C program:

found=0
while ...; do
   ...
  if something; then found=1; fi    # Found one!  Keep going.
   ...
done
if ((found)); then ...

Here is a function to convert numbers in other bases to decimal (base 10):

todec() {
    echo "$(( $1#$2 ))"
}

Examples:

todec 16 ffe    # -> 4094
todec 2 100100  # -> 36



Etc

FAIR USE NOTICE This site contains copyrighted material the use of which has not always been specifically authorized by the copyright owner. We are making such material available in our efforts to advance understanding of environmental, political, human rights, economic, democracy, scientific, and social justice issues, etc. We believe this constitutes a 'fair use' of any such copyrighted material as provided for in section 107 of the US Copyright Law. In accordance with Title 17 U.S.C. Section 107, the material on this site is distributed without profit exclusivly for research and educational purposes.   If you wish to use copyrighted material from this site for purposes of your own that go beyond 'fair use', you must obtain permission from the copyright owner. 

ABUSE: IPs or network segments from which we detect a stream of probes might be blocked for no less then 90 days. Multiple types of probes increase this period.  

Society

Groupthink : Two Party System as Polyarchy : Corruption of Regulators : Bureaucracies : Understanding Micromanagers and Control Freaks : Toxic Managers :   Harvard Mafia : Diplomatic Communication : Surviving a Bad Performance Review : Insufficient Retirement Funds as Immanent Problem of Neoliberal Regime : PseudoScience : Who Rules America : Neoliberalism  : The Iron Law of Oligarchy : Libertarian Philosophy

Quotes

War and Peace : Skeptical Finance : John Kenneth Galbraith :Talleyrand : Oscar Wilde : Otto Von Bismarck : Keynes : George Carlin : Skeptics : Propaganda  : SE quotes : Language Design and Programming Quotes : Random IT-related quotesSomerset Maugham : Marcus Aurelius : Kurt Vonnegut : Eric Hoffer : Winston Churchill : Napoleon Bonaparte : Ambrose BierceBernard Shaw : Mark Twain Quotes

Bulletin:

Vol 25, No.12 (December, 2013) Rational Fools vs. Efficient Crooks The efficient markets hypothesis : Political Skeptic Bulletin, 2013 : Unemployment Bulletin, 2010 :  Vol 23, No.10 (October, 2011) An observation about corporate security departments : Slightly Skeptical Euromaydan Chronicles, June 2014 : Greenspan legacy bulletin, 2008 : Vol 25, No.10 (October, 2013) Cryptolocker Trojan (Win32/Crilock.A) : Vol 25, No.08 (August, 2013) Cloud providers as intelligence collection hubs : Financial Humor Bulletin, 2010 : Inequality Bulletin, 2009 : Financial Humor Bulletin, 2008 : Copyleft Problems Bulletin, 2004 : Financial Humor Bulletin, 2011 : Energy Bulletin, 2010 : Malware Protection Bulletin, 2010 : Vol 26, No.1 (January, 2013) Object-Oriented Cult : Political Skeptic Bulletin, 2011 : Vol 23, No.11 (November, 2011) Softpanorama classification of sysadmin horror stories : Vol 25, No.05 (May, 2013) Corporate bullshit as a communication method  : Vol 25, No.06 (June, 2013) A Note on the Relationship of Brooks Law and Conway Law

History:

Fifty glorious years (1950-2000): the triumph of the US computer engineering : Donald Knuth : TAoCP and its Influence of Computer Science : Richard Stallman : Linus Torvalds  : Larry Wall  : John K. Ousterhout : CTSS : Multix OS Unix History : Unix shell history : VI editor : History of pipes concept : Solaris : MS DOSProgramming Languages History : PL/1 : Simula 67 : C : History of GCC developmentScripting Languages : Perl history   : OS History : Mail : DNS : SSH : CPU Instruction Sets : SPARC systems 1987-2006 : Norton Commander : Norton Utilities : Norton Ghost : Frontpage history : Malware Defense History : GNU Screen : OSS early history

Classic books:

The Peter Principle : Parkinson Law : 1984 : The Mythical Man-MonthHow to Solve It by George Polya : The Art of Computer Programming : The Elements of Programming Style : The Unix Haterís Handbook : The Jargon file : The True Believer : Programming Pearls : The Good Soldier Svejk : The Power Elite

Most popular humor pages:

Manifest of the Softpanorama IT Slacker Society : Ten Commandments of the IT Slackers Society : Computer Humor Collection : BSD Logo Story : The Cuckoo's Egg : IT Slang : C++ Humor : ARE YOU A BBS ADDICT? : The Perl Purity Test : Object oriented programmers of all nations : Financial Humor : Financial Humor Bulletin, 2008 : Financial Humor Bulletin, 2010 : The Most Comprehensive Collection of Editor-related Humor : Programming Language Humor : Goldman Sachs related humor : Greenspan humor : C Humor : Scripting Humor : Real Programmers Humor : Web Humor : GPL-related Humor : OFM Humor : Politically Incorrect Humor : IDS Humor : "Linux Sucks" Humor : Russian Musical Humor : Best Russian Programmer Humor : Microsoft plans to buy Catholic Church : Richard Stallman Related Humor : Admin Humor : Perl-related Humor : Linus Torvalds Related humor : PseudoScience Related Humor : Networking Humor : Shell Humor : Financial Humor Bulletin, 2011 : Financial Humor Bulletin, 2012 : Financial Humor Bulletin, 2013 : Java Humor : Software Engineering Humor : Sun Solaris Related Humor : Education Humor : IBM Humor : Assembler-related Humor : VIM Humor : Computer Viruses Humor : Bright tomorrow is rescheduled to a day after tomorrow : Classic Computer Humor

The Last but not Least


Copyright © 1996-2016 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. This document is an industrial compilation designed and created exclusively for educational use and is distributed under the Softpanorama Content License.

The site uses AdSense so you need to be aware of Google privacy policy. You you do not want to be tracked by Google please disable Javascript for this site. This site is perfectly usable without Javascript.

Original materials copyright belong to respective owners. Quotes are made for educational purposes only in compliance with the fair use doctrine.

FAIR USE NOTICE This site contains copyrighted material the use of which has not always been specifically authorized by the copyright owner. We are making such material available to advance understanding of computer science, IT technology, economic, scientific, and social issues. We believe this constitutes a 'fair use' of any such copyrighted material as provided by section 107 of the US Copyright Law according to which such material can be distributed without profit exclusively for research and educational purposes.

This is a Spartan WHYFF (We Help You For Free) site written by people for whom English is not a native language. Grammar and spelling errors should be expected. The site contain some broken links as it develops like a living tree...

You can use PayPal to make a contribution, supporting development of this site and speed up access. In case softpanorama.org is down you can use the at softpanorama.info

Disclaimer:

The statements, views and opinions presented on this web page are those of the author (or referenced source) and are not endorsed by, nor do they necessarily reflect, the opinions of the author present and former employers, SDNP or any other organization the author may be associated with. We do not warrant the correctness of the information provided or its fitness for any purpose.

Last modified: February 21, 2017