As a Bash scripter, performing various arithmetic operations on numbers is a common task. While Bash does have some basic math functionalities, the expr command offers efficient capabilities for mathematical calculations within Bash scripts.
In this comprehensive guide, we will explore how to leverage expr for multiplying, dividing as well as other numeric manipulations in Bash.
Understanding the Role of Expr for Math in Bash Scripts
The expr or expression command evaluates arguments as an expression and outputs the result. As per the POSIX standard, it can perform both numeric and string operations.
Here are some common use cases where expr comes handy:
- Multiplying or dividing numbers
- Finding remainder or modulus
- Adding or subtracting cumulated values
- Comparing numerical relation between two variables
- Finding length of a string
- Extracting substring based on index
Without expr, we would have to write external programs like awk, bc, Perl, Python etc. for mathematical operations in Bash – which can get messy.
The expr command provides a cleaner method for basic math right inside Bash itself. When combined with other text processing utilities like sed, grep, it unlocks many interesting use cases.
Performing Multiplication with Expr
Let‘s start with one of the most common numeric operations – multiplication.
Note: The
*symbol has special meaning in Bash for wildcard globbing. So we need to escape it as\*for multiplication inexpr.
Here is an example to multiply two integers:
#!/bin/bash
a=20
b=30
result=$(expr $a \* $b)
echo "$a * $b = $result"
On executing the above script, we get the output:
20 * 30 = 600
The key points regarding multiplication are:
- Use
\*for multiplying numbers instead of just* - Enclose the
exprexpression within$()to store the numeric result in a variable
We can also multiply variables containing string numbers like this:
a="4.5"
b="25"
result=$(expr "$a" \* "$b" )
echo "$a * $b = $result"
This multiplies the string numbers 4.5 and 25, resulting in 112.5.
One quirk to note here is that expr works only with integer numbers. For floating point or decimal numbers, the fractional part is simply truncated. We will explore this limitation of expr later on.
Multiplying a Column of Numbers from File
Let‘s try a practical example of multiplying an entire column of numbers from a text file with expr.
numbers.txt
2
4.5
10
3
Bash Script:
#!/bin/bash
total=1
while read num; do
total=$(expr $total \* $num)
done < numbers.txt
echo "Total: $total"
Here we initialize total as 1, read each number line by line from numbers.txt, multiply it with total and update total in each iteration of the loop.
This gives the final output as:
Total: 270
By combining expr with other Bash capabilities like input redirection and loops, we can easily accumulate mathematical computation on an entire file of data.
Dividing Numbers in Bash Scripts Using Expr
Similar to multiplication, expr also allows dividing two numbers using the / operator:
a=50
b=5
result=$(expr $a / $b)
echo "$a / $b = $result" # prints 10
The advantage is that unlike multiplication, we don‘t need to escape any special characters for division. The standard forward slash / works as is.
But one catch with division is that the remainder is truncated instead of rounded off.
For example:
result=$(expr 10 / 3)
echo "10 / 3 = $result"
# Prints 3 instead of 3.33 by dropping the .33 fraction
Later we will see how to retain precision for floating point numbers by integrating expr with other Linux tools like bc, awk etc.
Next, let us look at a few more mathematical operations that are possible with expr.
Performing Other Arithmetic Calculations
Beyond basic math functions like +, -, *, /, the expr command can evaluate some additional numeric operations.
Finding Remainder with % modulus
The % modulus operator gives the remainder left over after division.
For example:
result=$(expr 20 % 3)
echo "Remainder of 20 / 3 = $result" # 2
Finding whether a number is even or odd based on remainder is a good use case of modulus.
Incrementing and Decrementing values
We can easily increment or decrement a number variable using expr like so:
num=5
num=$(expr $num + 1) # Increment by 1
echo "$num" # Prints 6
num=$(expr $num - 2) # Decrement by 2
echo "$num" # Prints 4
These increment and decrement functionalities make expr quite useful for counters in scripts.
Comparing numerical relations
We can also compare numeric values using relational operators like:
>: Greater than<: Less than<=: Less than or equal to>=: Greater than or equal to==: Equal!=: Not equal
The condition result is output as 1 for TRUE or 0 for FALSE.
For instance:
result=$(expr 3 \> 2) # 1 (3 > 2 is true)
result=$(expr 3 \< 2) # 0 (3 < 2 is false)
This provides easy ways for numeric comparisons in Bash scripts.
Thus expr can evaluate a wide range of mathematical expressions by combining multiple operators.
Understanding Data Types and Calculations in Expr
Now that we have explored various mathematical operations possible through expr, let us understand how it handles different data types and precision.
Integer vs Floating Point Numbers
As mentioned before, expr works primarily with integer numbers and treats floats as integers by truncating the decimal part.
For example:
result=$(expr 10 / 3)
echo "$result" # 3 (truncates decimal)
For floating point arithmetic with full precision, expr needs to be used along with external programs like below:
result=$( echo "scale=2; 10/3" | bc)
echo "$result" # 3.33
Here bc is used along with expr to retain the precision in division.
In terms of data storage, integers take 4 bytes while floats are bigger with 8 bytes storage. So integer math with expr can be faster for certain tasks. But we lose out on precision.
Choosing between them depends on the specific use-case and trade-off between speed vs precision.
Number Bases and Support for Hex, Octal
By default. expr treats all numbers as decimal (base 10) integers. But expr can also work with hex and octal bases using 0x and 0 prefixes respectively.
For example:
result=$(expr 0xff + 1) # Hex addition
echo $result # 256
result=$(expr 0o77 \* 2) # Octal multiplication
echo $result # 126
So we have necessary support for number representations in different bases.
Handling Large Numbers and Overflow
For integer math, expr works reliably within a certain range, but can overflow beyond machine word size limits. On 64 bit Bash, maximum integer value is 9223372036854775807.
There is no overflow protection by default. So we have to perform those checks explicitly.
Here is an example overflow scenario:
max_int=9223372036854775807
result=$(expr $max_int + 1)
# Prints -9223372036854775808
The result wraps around the maximum integer limit since the underlying data type has no room to store higher value.
So when working with very large numbers in expr, we need extra caution, bounds checking and handling overflows through scripts.
Best Practices for Using Expr Efficiently
While using the expr command for numeric calculations in Bash, following some basic guidelines and best practices will help:
- Enclose the
exprstatements in$( )syntax and store output in variable for easier manipulation - For multiplication use escape
\with*operator - When using floating point numbers, combine with
bc,awketc. for precision - Validate integer calculations for overflows depending on use case
- Use relational operators like
>,<etc. for numeric comparisons - Favor integer math over floating point when speed is critical
- Ensure proper spacing between operators, variables and numbers in the expression
- Use braces {} to clearly distinguish var names like ${var} from literal numbers
- Add error checking with custom helper functions for invalid cases
Sticking to these best practices will result in clean, maintainable and robust Bash scripts with math operations.
Common Errors and Troubleshooting Expr Usage
While leveraging expr for numeric calculations in Bash, some common errors we may encounter include:
Spaces between operators
No spaces are allowed between expr operators. Otherwise we get syntax errors:
result=$(expr 15 + 5) # Error
# Add space between + and 5
Unescaped * multiplication
Forgetting to escape * leads to incorrect glob pattern multiplication instead of math multiplication.
Precedence order not followed
Expressions are evaluated according to precedence order. Not following rules leads to unintended results.
Incorrect data type
Passing string to mathematical operators like / or % causes runtime errors.
Uninitialized variables
Using unintitialized variables in expression causes errors.
By learning about these pitfall scenarios, we can design defensive checks, validate inputs and troubleshoot script issues faster.
Integrating Expr with Other Unix Commands
One of the main advantages of expr math in Bash is that it works smoothly with other UNIX commands through pipelines. Let us take some examples:
Find length of a string
We can output the length of a string by piping to expr:
var="Welcome to LinuxHint"
echo "$var" | expr length # 24
Here length parameter gives back the string size.
Extract substring
It is possible to extract a substring from a specific index using expr like so:
var="LinuxHint"
expr substr "$var" 3 6 # xHint
This extracts a substring between index 3 to 6.
Regex match with strings
We can even match regular expression pattern against a string input using expr.
For example:
var="Learn Bash Scripting"
echo $var | expr match "$var" ‘.*Scripting‘ # 18 (matches)
Here match regex parameter returns the match status.
Thus expr allows integrating string processing capabilities in conjunction with numeric calculations within Bash scripts.
Comparison Between Expr and Other Math Tools for Bash
While expr offers efficient math evaluation, there are also few other prominent tools and programming languages used for mathematical operations in Linux and Bash:
| Feature | Expr | Awk | Python | Perl |
|---|---|---|---|---|
| Integration with Bash | Excellent | Very Good | Good | Minimal |
| Readability of code | Moderate | Moderate | Excellent | Low |
| Performance | Very Fast | Fast | Moderate | Very fast for math operations |
| Error Handling | Minimal | Minimal | Robust Exception Handling | Robust and configurable error handling |
| Graphing and Visualization Libraries | None | Basic | Highly Mature (matplotlib etc.) | Limited capabilities |
| Floating Point Precision | Fixed point only, lacks FP precision | Excellent precision | Flexible precision | Adjustable precision |
So while expr is great for simple use cases needing integer math and tight Bash system integration, when advanced math capabilities are needed – alternate tools like Python and Perl may be better suited.
But a huge benefit of expr is that we avoid introducing additional runtime dependencies like Python and Perl interpreters. Expr gives decent math abilities using only native Bash features.
Conclusion
Performing basic arithmetic with integers and strings right within Bash scripts is made simpler with the expr command. It evaluates numerical and string expressions by acting as an interpreter for the arguments passed to it.
For basic multiplication, division, modulus operations with good performance – expr fits the bill nicely. For advanced floating point math and graphing features – external programs can be utilized.
By mastering the expr command, Bash programmers can write concise yet powerful scripts for crunching numbers as part of their daily text processing needs in Linux environment.


