< Day Day Up > 

An expression is composed of constants, variables, and operators that can be processed to return a value. This section covers arithmetic, logical, and conditional expressions as well as operators. Table 11-8 on page 505 lists the bash operators.

Table 11-8. Operators

Type of operator/operator
















Unary minus


Unary plus




Boolean NOT (logical negation)


Complement (bitwise negation)





Multiplication, division,remainder








Addition, subtraction





Bitwise shifts



Left bitwise shift


Right bitwise shift




Less than or equal


Greater than or equal


Less than


Greater than

Equality, inequality


= =







Bitwise AND


Bitwise XOR (exclusive OR)


Bitwise OR

Boolean (logical)



Boolean AND


Boolean OR

Conditional evaluation


? :

Ternary operator



=, *=, /=, %=, + =, =,

<< =, >>=, &=, ^=, |=






Arithmetic Evaluation

The Bourne Again Shell can perform arithmetic assignments and evaluate many different types of arithmetic expressions, all using integers. The shell performs arithmetic assignments in a number of ways. One is with arguments to the let builtin:

 $ let "VALUE=VALUE * 10  + NEW" 

In the preceding example, the variables VALUE and NEW contain integer values. Within a let statement you do not need to use dollar signs ($) in front of variable names. Double quotation marks must enclose a single argument, or expression, that contains SPACEs. Because most expressions contain SPACEs and need to be quoted, bash accepts ((expression)) as a synonym for let "expression", obviating the need for both quotation marks and dollar signs:

 $ ((VALUE=VALUE * 10 + NEW)) 

You can use either form wherever a command is allowed and can remove the SPACEs if you like. In the following example, the asterisk (*) does not need to be quoted because the shell does not perform pathname expansion on the right side of an assignment (page 280):

 $ let VALUE=VALUE*10+NEW 

Because each argument to let is evaluated as a separate expression, you can assign values to more than one variable on a single line:

 $ let "COUNT = COUNT + 1" VALUE=VALUE*10 +NEW 

You need to use commas to separate multiple assignments within a set of double parentheses:

 $ ((COUNT = COUNT + 1, VALUE=VALUE*10 +NEW)) 

tip: Arithmetic evaluation versus arithmetic expansion

Arithmetic evaluation differs from arithmetic expansion. As explained on page 327, arithmetic expansion uses the syntax $((expression)), evaluates expression, and replaces $((expression)) with the result. You can use arithmetic expansion to display the value of an expression or to assign that value to a variable.

Arithmetic evaluation uses the let expression or ((expression)) syntax, evaluates expression, and returns a status code. You can use arithmetic evaluation to perform a logical comparison or an assignment.

Logical expressions

You can use the ((expression)) syntax for logical expressions, although that task is frequently left to [[expression]]. The next example expands the age_check script (page 327) to include logical arithmetic evaluation in addition to arithmetic expansion:

 $ cat age2 #!/bin/bash echo -n "How old are you? " read age if ((30 < age && age < 60)); then         echo "Wow, in $((60-age)) years, you'll be 60!"     else         echo "You are too young or too old to play." fi $ age2 How old are you? 25 You are too young or too old to play. 

The test-statement for the if structure evaluates two logical comparisons joined by a Boolean AND and returns 0 (true) if they are both true or 1 (false) otherwise.

Logical Evaluation (Conditional Expressions)

The syntax of a conditional expression is

 [[ expression ]] 

where expression is a Boolean (logical) expression. You must precede a variable name with a dollar sign ($) within expression. The result of executing this builtin, like the test builtin, is a return status. The conditions allowed within the brackets are almost a superset of those accepted by test (page 794). Where the test builtin uses a as a Boolean AND operator, [[ expression ]] uses &&. Similarly, where test uses o as a Boolean OR operator, [[ expression ]] uses ||.

You can replace the line that tests age in the age2 script (preceding) with the following conditional expression. You must surround the [[ and ]] tokens with whitespace or a command terminator, and place dollar signs before the variables:

 if [[ 30 < $age && $age < 60 ]]; then 

You can also use test's relational operators gt, ge, lt, le, eq, and ne :

 if [[ 30 -lt $age && $age -lt 60 ]]; then 

String comparisons

The test builtin tests whether strings are equal or unequal. The [[ expression ]] syntax adds comparison tests for string operators. The > and < operators compare strings for order (for example, "aa" < "bbb"). The = operator tests for pattern match, not just equality: [[ string = pattern ]] is true if string matches pattern. This operator is not symmetrical; the pattern must appear on the right side of the equal sign. For example, [[ artist = a* ]] is true (= 0), whereas [[ a* = artist ]] is false (= 1):

 $ [[ artist = a* ]] $ echo $? 0 $ [[ a* = artist ]] $ echo $? 1 

The next example uses a command list that starts with a compound condition. The condition tests that the directory bin and the file src/myscript.bash exist. If this is true, cp copies src/myscript.bash to bin/myscript. If the copy succeeds, chmod makes myscript executable. If any of these steps fails, echo displays a message.

 $ [[ -d bin && -f src/myscript.bash ]] && cp src/myscript.bash \ bin/myscript && chmod +x bin/myscript || echo "Cannot make \ executable version of myscript" 

String Pattern Matching

The Bourne Again Shell provides string pattern-matching operators that can manipulate pathnames and other strings. These operators can delete from strings prefixes or suffixes that match patterns. The four operators are listed in Table 11-7.

Table 11-7. String operators




Removes minimal matching prefixes


Removes maximal matching prefixes


Removes minimal matching suffixes


Removes maximal matching suffixes

The syntax for these operators is

 ${varname op pattern} 

where op is one of the operators listed in Table 11-7 and pattern is a match pattern similar to that used for filename generation. These operators are commonly used to manipulate pathnames so as to extract or remove components or to change suffixes:

 $ SOURCEFILE=/usr/local/src/prog.c $ echo ${SOURCEFILE#/*/} local/src/prog.c $ echo ${SOURCEFILE##/*/} prog.c $ echo ${SOURCEFILE%/*} /usr/local/src $ echo ${SOURCEFILE%%/*} $ echo ${SOURCEFILE%.c} /usr/local/src/prog $ CHOPFIRST=${SOURCEFILE#/*/} $ echo $CHOPFIRST local/src/prog.c $ NEXT=${CHOPFIRST%%/*} $ echo $NEXT local 

Here the string-length operator, ${#name}, is replaced by the number of characters in the value of name:

 $ echo $SOURCEFILE /usr/local/src/prog.c $ echo ${#SOURCEFILE} 21 


Arithmetic expansion and arithmetic evaluation use the same syntax, precedence, and associativity of expressions as the C language. Table 11-8 lists operators in order of decreasing precedence (priority of evaluation); each group of operators has equal precedence. Within an expression you can use parentheses to change the order of evaluation.


The pipe token has higher precedence than operators. You can use pipes anywhere in a command that you can use simple commands. For example, the command line

 $ cmd1 | cmd2 || cmd3 | cmd4 && cmd5 | cmd6 

is interpreted as if you had typed

 $ ((cmd1 | cmd2) || (cmd3 | cmd4)) && (cmd5 | cmd6) 

tip: Do not rely on rules of precedence: use parentheses

Do not rely on the precedence rules when you use compound commands. Instead, use parentheses to explicitly state the order in which you want the shell to interpret the commands.

Increment and decrement operators

The postincrement, postdecrement, preincrement, and predecrement operators work with variables. The pre- operators, which appear in front of the variable name as in ++COUNT and VALUE, first change the value of the variable (++ adds 1; subtracts 1) and then provide the result for use in the expression. The post- operators appear after the variable name as in COUNT++ and VALUE ; they first provide the unchanged value of the variable for use in the expression and then change the value of the variable.

 $ N=10 $ echo $N 10 $ echo $((--N+3)) 12 $ echo $N 9 $ echo $((N++ - 3)) 6 $ echo $N 10 


The remainder operator (%) gives the remainder when its first operand is divided by its second. For example, the expression $((15%7)) has the value 1.


The result of a Boolean operation is either 0 (false) or 1 (true).

The && (AND) and || (OR) Boolean operators are called short-circuiting operators. If the result of using one of these operators can be decided by looking only at the left operand, the right operand is not evaluated. The && operator causes the shell to test the exit status of the command preceding it. If the command succeeded, bash executes the next command; otherwise, it skips the remaining commands on the command line. You can use this construct to execute commands conditionally:

 $ mkdir bkup && cp -r src bkup 

This compound command creates the directory bkup. If mkdir succeeds, the contents of directory src is copied recursively to bkup.

The || separator also causes bash to test the exit status of the first command but has the opposite effect: The remaining command(s) are executed only if the first one failed (that is, exited with nonzero status):

 $ mkdir bkup || echo "mkdir of bkup failed" >> /tmp/log 

The exit status of a command list is the exit status of the last command in the list. You can group lists with parentheses. For example, you could combine the previous two examples as

 $ (mkdir bkup && cp -r src bkup) || echo "mkdir failed" >> /tmp/log 

In the absence of parentheses, && and || have equal precedence and are grouped from left to right. The following examples use the true and false utilities. These utilities do nothing and return true (0) and false (1) exit statuses, respectively:

 $ false; echo $? 1 

The $? variable holds the exit status of the preceding command (page 479). The next two commands yield an exit status of 1 (false):

 $ true || false && false $ echo $? 1 $ (true || false) && false $ echo $? 1 

Similarly the next two commands yield an exit status of 0 (true):

 $ false && false || true $ echo $? 0 $ (false && false) || true $ echo $? 0 

Because || and && have equal precedence, the parentheses in the two preceding pairs of examples do nothing to change the order of operations.

Because the expression on the right side of a short-circuiting operator may never get executed, you must be careful with assignment statements in that location. The following example demonstrates what can happen:

 $ ((N=10,Z=0)) $ echo $((N || ((Z+=1)) )) 1 $ echo $Z 0 

Because the value of N is nonzero, the result of the || (OR) operation is 1 (true), no matter what the value of the right side is. As a consequence ((Z+=1)) is never evaluated and Z is not incremented.


The ternary operator, ? : , decides which of two expressions should be evaluated, based on the value returned from a third expression:

 expression1 ? expression2 : expression3 

If expression1 produces a false (0) value, expression3 is evaluated; otherwise, expression2 is evaluated. The value of the entire expression is the value of expression2 or expression3, depending on which one is evaluated. If expression1 is true, expression3 is not evaluated. If expression1 is false expression2 is not evaluated:

 $ ((N=10,Z=0,COUNT=1)) $ ((T=N>COUNT?++Z:--Z)) $ echo $T 1 $ echo $Z 1 


The assignment operators, such as + =, are shorthand notations. For example, N+ =3 is the same as ((N=N+3)).

Other bases

The following commands use the syntax base#n to assign base 2 (binary) values. First v1 is assigned a value of 0101 (5 decimal) and v2 is assigned a value of 0110 (6 decimal). The echo utility verifies the decimal values.

 $ ((v1=2#0101)) $ ((v2=2#0110)) $ echo "$v1 and $v2" 5 and 6 

Next the bitwise AND operator (&) selects the bits that are on in both 5 (0101 binary) and 6 (0110 binary). The result is binary 0100, which is 4 decimal.

 $ echo $(( v1 & v2 )) 4 

The Boolean AND operator (&&) produces a result of 1 if both of its operands are nonzero and a result of 0 otherwise. The bitwise inclusive OR operator (|) selects the bits that are on in either 0101 or 0110, resulting in 0111, which is 7 decimal. The Boolean OR operator (| |) produces a result of 1 if either of its operands is nonzero and a result of 0 otherwise.

 $ echo $(( v1 && v2 )) 1 $ echo $(( v1 | v2 )) 7 $ echo $(( v1 || v2 )) 1 

Next the bitwise exclusive OR operator (^) selects the bits that are on in either, but not both, of the operands 0101 and 0110, yielding 0011, which is 3 decimal. The Boolean NOT operator (!) produces a result of 1 if its operand is 0 and a result of 0 otherwise. Because the exclamation point in $(( ! v1 )) is enclosed within double parentheses, it does not need to be escaped to prevent the shell from interpreting the exclamation point as a history event. The comparison operators produce a result of 1 if the comparison is true and a result of 0 otherwise.

 $ echo $(( v1 ^ v2 )) 3 $ echo $(( ! v1 )) 0 $ echo $(( v1 < v2 )) 1 $ echo $(( v1 > v2 )) 0 

     < Day Day Up > 

    A Practical Guide to LinuxR Commands, Editors, and Shell Programming
    A Practical Guide to LinuxR Commands, Editors, and Shell Programming
    ISBN: 131478230
    EAN: N/A
    Year: 2005
    Pages: 213 © 2008-2017.
    If you may any questions please contact us: