+----------------------------------------------+
|Expression
Output
Exit Status |
+----------------------------------------------+
|expr '' | ''
0
1
|
|expr '' | 0
0
1
|
|expr '' | 1
1
0
|
|expr '' | A
A
0
|
|expr 0 | ''
0
1
|
|expr 0 | 1
1
0
|
|expr 0 | A
A
0
|
|expr 1 | anything
1
0
|
|expr A | anything
A
0
|
|expr '' & anything
0
1
|
|expr 0 & anything
0
1
|
|expr 1 & ''
0
1
|
|expr 1 & 0
0
1
|
|expr 1 & A
1
0
|
|expr A & ''
0
1
|
|expr A & 0
0
1
|
|expr A & 1
A
0
|
|expr A & B
A
0
|
+----------------------------------------------+
The string operator
The last operator is the string operation. It is also the most complicated. The syntax is
string : regular-expression
The regular expression is assumed to have a "^" in front of it, so it always is aligned with the first character of
the string. The output is the numbers of characters matched in the regular expression. That is,
expr abc : abc
outputs "3," while
expr abc : abd
outputs "0." As you can see, if it doesn't match, a zero is returned, the equivalent of "false." If a match
occurs, a true value (non-zero) is returns, and you know how many characters match. This can be used to
count characters, letters or numbers:
# prints the number characters in variable a
expr "$a" : '.*'
# prints the number of lower case letters
expr "$a" : '[a-z]*'
# prints the number of lower case letters
expr "$a" : '[0-9]*'
Remember, the regular expression starts at the first character, so the last example will only count numbers at
the beginning of the variable. If variable "a" has the value of "123abc" the expression would return a value of
three. Expr returns the number of characters matched. Therefore, expr can be used to find the location of the
first letter in a string:
expr "$x" : '[^a-zA-Z]*[a-zA-Z]'
Bourne Shell Tutorial
http://www.grymoire.com/Unix/Sh.html
55 of 66
11/21/2011 12:03 PM
Parenthesis can be used
in the regular expression, like the substitute command in sed. If a match is found, the
substring within the parenthesis is returned. Therefore, if the variable "a" has the value "123abc," the two
commands below output the same string, which is "abc."
# if $a = 123abc, then output 'abc'
expr "$a" : '[0-9]*([a-z]*)'
# same as above
echo $a | sed 's/^[0-9]*([a-z]*)/1/'
This feature is often used to extract part of a command line option. You should know that the parenthesis
must have a back-slash before them, and expr must see them. That is, the backslash is not a signal to the shell
that the following character is not a meta-character. The reason it must be excaped is to match the same
syntax as sed, etc. Suppose you had a shell script with the following option
myscript -x123
Now suppose you wanted to extract the number from the option. You could use a sed script like the one
above. You could also use the expr command:
x=`expr "$1" : '-x(.*)'`
The expr command can also be used to test if a variable is a number:
echo "Type in a number"
read ans
number=`expr "$ans" : "([0-9]*)"`
if [ "$number" != "$ans" ]; then
echo "Not a number"
elif [ "$number" -eq 0 ]; then
echo "Nothing was typed"
else
echo "$number is a fine number"
fi
You can combine tests. For instance, the following will truncate a string to four characters:
expr "$x" : '(....)' | "$x"
The results of each expression is another expression, so you can combine expressions. The following prints
32:
expr 2 + 3 * 10
The expr command can even be used as a simple version of basename. The following will output the last part
of a filename:
expr "$x" : '.*/(.*)' '|' "$x"
However, there is a bug in this code. If the variable "x" is equal to "/," then this evaluates to
expr / : '.*/(.*)' '|' /
If you remember, I pointed out this problem earlier. The shell assumes the slash is an operator, and not an
Bourne Shell Tutorial
http://www.grymoire.com/Unix/Sh.html
56 of 66
11/21/2011 12:03 PM
expression. It complains about the syntax error. The solution is to place slashes before the variable:
expr //$x : '.*/(.*)'
Precedence of the Operators
You can place parenthesis around expressions to construct more complex expressions. Make sure you quote
them, as the shell treats parenthesis as special characters..
expr ( 2 + 3 ) * 10
The parenthesis overrides the default precedence, and the results is 50, to 32. These parenthesis are different
than the ones used in regular expressions to perform a substitute operation. Expr should see the parenthesis
without backslashes. The backslashes are for the shell. You could use quotes instead of backslashes. The
natural precedence is grouped into six different levels, which are:
+-------------------+
|Highest Precedence |
+-------------------+
|
expr : expr
|
+-------------------+
|
expr * expr
|
|
expr / expr
|
|
expr % expr
|
+-------------------+
|
expr + expr
|
|
expr - expr
|
+-------------------+
|
expr = expr |
| expr > expr
|
| expr >= expr
|
| expr < expr
|
| expr <= expr
|
|
expr != expr
|
+-------------------+
| expr expr
|
+-------------------+
|
expr expr
|
+-------------------+
|Lowest Precedence
|
+-------------------+
Berkeley Extensions
The Berkeley version of expr has three special functions:
match
substr
length
The match operator acts like the colon. The substring operator acts like the awk function. The length operator
returns the length of a string. I suggest you do not use them, for portability reasons. You do get this
functionality if you place the directory "/usr/ucb" before either "/usr/bin" on Solaris, or "/usr/5bin" on SunOS.
It doesn't matter if you use the build-in version, or the external version. Both versions support the Berkeley
Bourne Shell Tutorial
http://www.grymoire.com/Unix/Sh.html
57 of 66
11/21/2011 12:03 PM