In Part 7 of the Linux Bash Course, we cover the logic systems that control script execution. You will learn legacy and modern command arithmetic methods, how to calculate floating-point numbers with bc, how to build conditional ladders, test file properties, and execute various loop patterns.
For deep-dive rules on conditional expressions, see the GNU Bash Manual - Conditional Expressions.
Chapter 19: Arithmetic & Expressions
19.1 The expr Command (Legacy)
expr is an external utility used in legacy Bourne shells to evaluate expressions. It only supports basic integer arithmetic and requires spaces between numbers and operators. Multiplication signs (*) must be escaped to prevent shell wildcard expansion.
- Syntax:
expr value1 operator value2 - Example Command:
expr 10 \* 5 - Expected Output:
50 - Flag & Command Breakdown:
\*: The multiplication symbol must be escaped with a backslash in the terminal to prevent the shell from interpreting it as a wildcard file expansion pattern.
19.2 Double Parentheses: $(( ... ))
Modern Bash scripts use double parentheses $(( ... )) for integer calculations. This syntax runs faster than expr because it is built directly into the shell process, and it does not require escaping operators or spacing out components.
- Syntax:
result=$((expression)) - Example Command:
NUM1=20 NUM2=5 RESULT=$((NUM1 * NUM2 + 10)) echo "Calculated: $RESULT" - Expected Output:
Calculated: 110
19.3 Incrementing and Decrementing: ((i++))
Inside arithmetic brackets, you can perform post/pre-incrementing and post/pre-decrementing using C-style math notations. This is commonly used in loop counters.
- Syntax:
((variable++)) ((variable--)) - Example Command:
COUNTER=5 ((COUNTER++)) echo "Post-increment: $COUNTER" ((COUNTER--)) echo "Post-decrement: $COUNTER" - Expected Output:
Post-increment: 6 Post-decrement: 5
19.4 The let Command
let is a Bash shell built-in command that evaluates math expressions and directly assigns the result to a variable. Like $(( )), it only supports integer arithmetic.
- Syntax:
let "variable = expression" - Example Command:
let "SUM = 10 + 20" "PROD = SUM * 2" echo "Sum: $SUM, Product: $PROD" - Expected Output:
Sum: 30, Product: 60
19.5 Arithmetic with bc (Floating Point)
Bash cannot natively compute floating-point (decimal) numbers; $(( 5 / 2 )) yields 2. To solve this, we pipe mathematical statements into bc (An arbitrary precision calculator language utility).
- Syntax:
echo "expression" | bc - Example Command:
echo "5 / 2" | bc echo "5 / 2.0" | bc -l - Expected Output:
2 2.50000000000000000000 - Flag & Command Breakdown:
-l: Loads the standard math library, which sets the default precision (scale) to 20 decimal places.
19.6 Setting Precision in bc
To limit decimal precision when using bc, prepend the equation with the scale variable definition followed by a semicolon.
- Syntax:
echo "scale=decimal_places; expression" | bc - Example Command:
echo "scale=2; 10 / 3" | bc - Expected Output:
3.33
19.7 Hexadecimal and Octal Math
You can perform math in different bases by defining input/output bases using the ibase and obase settings inside the bc utility.
- Syntax:
echo "ibase=input_base; obase=output_base; expression" | bc - Example Command:
# Convert Hexadecimal FF to decimal echo "ibase=16; FF" | bc # Convert decimal 15 to binary echo "obase=2; 15" | bc - Expected Output:
255 1111
19.8 Random Number Generation: $RANDOM
$RANDOM is a built-in shell variable that returns a pseudo-random integer between 0 and 32767 each time it is accessed. To scale this number to a specific range (e.g., between 1 and 10), use the modulo operator (%).
- Syntax:
$(( RANDOM % range + offset )) - Example Command:
# Generate random number between 1 and 100 RAND_VAL=$(( (RANDOM % 100) + 1 )) echo "Generated: $RAND_VAL" - Expected Output:
Generated: 42
19.9 Sequencing with seq
The seq utility generates a sequence of numbers from a specified start value to an end value, with an optional step value.
- Syntax:
seq [start] [step] [end] - Example Command:
seq 1 2 5 - Expected Output:
1 3 5
19.10 Evaluating Expressions: [[ ... ]]
In modern Bash, double square brackets [[ ... ]] are used to evaluate expressions and test conditions. This is a shell keyword, which makes it safer and more feature-rich than the legacy POSIX [ ... ] command.
- Syntax:
[[ condition ]] - Example Command:
STR="tech" [[ -n "$STR" ]] echo $? - Expected Output:
0 - Flag & Command Breakdown:
-n: Checks if the string length is non-zero. Returns0(true) if it contains characters.
Chapter 20: Conditional Statements (if/else)
20.1 Syntax of if-then
The if statement executes a block of code only if the specified command or test expression returns an exit status of 0 (success).
- Syntax:
if [[ condition ]]; then # commands fi - Example Command:
VAL=10 if [[ $VAL -eq 10 ]]; then echo "Condition Met" fi - Expected Output:
Condition Met
20.2 if-then-else
The else block executes alternative commands if the test expression returns a non-zero exit status.
- Syntax:
if [[ condition ]]; then # commands when true else # commands when false fi - Example Command:
VAL=5 if [[ $VAL -eq 10 ]]; then echo "Ten" else echo "Not Ten" fi - Expected Output:
Not Ten
20.3 if-elif-else Ladder
To evaluate multiple conditions in sequence, chain them using the elif (else-if) block.
- Syntax:
if [[ cond1 ]]; then # commands elif [[ cond2 ]]; then # commands else # commands fi - Example Command:
SCORE=85 if [[ $SCORE -ge 90 ]]; then echo "Grade A" elif [[ $SCORE -ge 80 ]]; then echo "Grade B" else echo "Grade C" fi - Expected Output:
Grade B
20.4 Nested if Statements
You can nest if statements inside another if block to evaluate dependent conditions.
- Example Script:
#!/bin/bash USER_TYPE="admin" LOGGED_IN=true if [[ "$LOGGED_IN" = true ]]; then if [[ "$USER_TYPE" = "admin" ]]; then echo "Access granted: Admin Dashboard." else echo "Access granted: Standard Portal." fi else echo "Error: Authentication required." fi
20.5 Test Command: [ ] vs [[ ]]
-
[ ](Single Brackets): Runs the POSIX/usr/bin/testutility. It requires careful quoting of variables to avoid syntax errors from word splitting and path expansion. -
[[ ]](Double Brackets): An extended shell keyword supported by Bash, Zsh, and Ksh. It handles empty variables and file wildcards safely, and it supports pattern matching (==) and regular expressions (=~) without throwing errors. -
Example Comparison:
EMPTY_VAR="" # This throws a syntax error: [ $EMPTY_VAR = "test" ] # This evaluates safely without throwing errors: [[ $EMPTY_VAR = "test" ]]
20.6 String Comparisons (=, !=, -z)
Common string test operators inside [[ ]]:
-
=: Checks if strings are equal. -
!=: Checks if strings are not equal. -
-z: Checks if the string is empty (length is zero). -
-n: Checks if the string is not empty. -
Syntax:
[[ "$string1" = "$string2" ]] [[ -z "$string" ]] -
Example Command:
USER_ROLE="developer" if [[ -z "$USER_ROLE" ]]; then echo "Role is unset" elif [[ "$USER_ROLE" = "developer" ]]; then echo "Access: IDE" fi -
Expected Output:
Access: IDE
20.7 Numeric Comparisons (-eq, -lt, -gt)
Because Bash handles double brackets as string tests by default, you must use specific operators for mathematical comparisons:
-
-eq: Equal to -
-ne: Not equal to -
-lt: Less than -
-le: Less than or equal to -
-gt: Greater than -
-ge: Greater than or equal to -
Syntax:
[[ num1 -eq num2 ]] -
Example Command:
LIMIT=100 COUNT=80 if [[ $COUNT -lt $LIMIT ]]; then echo "Under limit" fi -
Expected Output:
Under limit
20.8 File Tests (-f, -d, -e, -x)
File test operators check files and folders on the filesystem:
-
-e: Checks if the file or folder exists. -
-f: Checks if it exists and is a regular file. -
-d: Checks if it exists and is a directory. -
-r: Checks if the file is readable. -
-w: Checks if the file is writable. -
-x: Checks if the file is executable. -
Syntax:
[[ -f /path/to/file ]] -
Example Command:
TARGET="/etc/passwd" if [[ -f "$TARGET" ]]; then echo "$TARGET exists and is a regular file." fi -
Expected Output:
/etc/passwd exists and is a regular file.
20.9 Logical AND (&&) and OR (||)
You can combine multiple test conditions inside double brackets:
-
&&: Logical AND. Both conditions must be true. -
||: Logical OR. At least one condition must be true. -
Syntax:
[[ cond1 && cond2 ]] [[ cond1 || cond2 ]] -
Example Command:
USER="root" SYS_LOAD=5 if [[ "$USER" = "root" && $SYS_LOAD -lt 10 ]]; then echo "System admin access approved." fi -
Expected Output:
System admin access approved.
20.10 Using case for Multiple Conditions
The case statement is a switch-like structure. It evaluates a value against multiple patterns and executes the block associated with the first match. Patterns can include wildcards (like * or ?) and the pipe symbol (|) for logical OR. Each block must end with double semicolons (;;).
- Syntax:
case $variable in pattern1) # commands ;; pattern2|pattern3) # commands ;; *) # default commands ;; esac - Example Command:
OS_TYPE="Ubuntu" case "$OS_TYPE" in "Ubuntu"|"Debian") echo "Installer: apt" ;; "CentOS"|"RHEL") echo "Installer: yum" ;; *) echo "Installer unknown" ;; esac - Expected Output:
Installer: apt
Chapter 21: Loops in Bash
21.1 for Loop over a List
The standard for loop iterates over a list of space-separated items, executing the loop body once for each element.
- Syntax:
for item in list; do # commands done - Example Command:
for server in web01 database cache01; do echo "Deploying to: $server" done - Expected Output:
Deploying to: web01 Deploying to: database Deploying to: cache01
21.2 for Loop with Range ({1..10})
You can use brace expansion {start..end..step} to generate ranges of numbers or characters dynamically.
- Syntax:
for i in {start..end..step}; do # commands done - Example Command:
for i in {2..6..2}; do echo "Count: $i" done - Expected Output:
Count: 2 Count: 4 Count: 6
21.3 C-Style for Loop
The C-style for loop is ideal for mathematical loop counters. It uses a three-expression structure: initialization, evaluation, and step increment.
- Syntax:
for ((init; condition; step)); do # commands done - Example Command:
for ((i=1; i<=3; i++)); do echo "Iteration: $i" done - Expected Output:
Iteration: 1 Iteration: 2 Iteration: 3
21.4 The while Loop
The while loop runs repeatedly as long as the test condition returns an exit status of 0 (success).
- Syntax:
while [[ condition ]]; do # commands done - Example Command:
COUNTER=3 while [[ $COUNTER -gt 0 ]]; do echo "Tick: $COUNTER" ((COUNTER--)) done - Expected Output:
Tick: 3 Tick: 2 Tick: 1
21.5 Infinite Loops (while true)
An infinite loop runs indefinitely unless it encounters a break statement or is terminated by an external process signal. The built-in commands true and : always return success.
- Syntax:
while true; do # commands done - Example Script:
#!/bin/bash while true; do echo "Monitoring process logs..." sleep 5 done
21.6 The until Loop (Opposite of while)
Unlike while, the until loop executes repeatedly as long as the test condition returns a failure status (non-zero). It terminates when the condition evaluates to success (0).
- Syntax:
until [[ condition ]]; do # commands done - Example Command:
COUNT=1 until [[ $COUNT -gt 3 ]]; do echo "Count: $COUNT" ((COUNT++)) done - Expected Output:
Count: 1 Count: 2 Count: 3
21.7 Reading File Lines with while read
Combining a while loop with the read command allows you to process text files line-by-line in a stream.
- Syntax:
while read -r variable; do # commands done < file.txt - Example Command:
printf "Service A\nService B\n" > status.log while read -r service; do echo "Status check: $service" done < status.log - Expected Output:
Status check: Service A Status check: Service B
21.8 Loop Control: break
The break statement exits the active loop immediately, skipping any remaining code in the loop body.
- Syntax:
break - Example Command:
for val in 1 2 3 4 5; do if [[ $val -eq 3 ]]; then break fi echo "Val: $val" done - Expected Output:
Val: 1 Val: 2
21.9 Loop Control: continue
The continue statement skips the rest of the current loop iteration and immediately starts the next one.
- Syntax:
continue - Example Command:
for val in 1 2 3; do if [[ $val -eq 2 ]]; then continue fi echo "Val: $val" done - Expected Output:
Val: 1 Val: 3
21.10 Nested Loops
You can run loops inside other loops to iterate over multidimensional grids or nested directories.
- Example Command:
for x in A B; do for y in 1 2; do echo "Coordinates: $x$y" done done - Expected Output:
Coordinates: A1 Coordinates: A2 Coordinates: B1 Coordinates: B2