How to use conditionals in shell scripts
How to Use Conditionals in Shell Scripts
Shell script conditionals are fundamental programming constructs that enable scripts to make decisions and execute different code paths based on specific conditions. Whether you're automating system administration tasks, processing files, or building complex deployment scripts, understanding how to effectively use conditionals is essential for creating robust and intelligent shell scripts.
This comprehensive guide will take you through everything you need to know about using conditionals in shell scripts, from basic if statements to advanced conditional techniques. You'll learn how to test various conditions, handle multiple scenarios, and implement best practices that will make your scripts more reliable and maintainable.
Table of Contents
1. [Prerequisites and Requirements](#prerequisites-and-requirements)
2. [Understanding Shell Script Conditionals](#understanding-shell-script-conditionals)
3. [Basic If Statements](#basic-if-statements)
4. [Test Operators and Conditions](#test-operators-and-conditions)
5. [Advanced Conditional Structures](#advanced-conditional-structures)
6. [Case Statements](#case-statements)
7. [Logical Operators](#logical-operators)
8. [Practical Examples and Use Cases](#practical-examples-and-use-cases)
9. [Common Issues and Troubleshooting](#common-issues-and-troubleshooting)
10. [Best Practices and Professional Tips](#best-practices-and-professional-tips)
11. [Conclusion](#conclusion)
Prerequisites and Requirements
Before diving into shell script conditionals, ensure you have the following:
System Requirements
- A Unix-like operating system (Linux, macOS, or WSL on Windows)
- Access to a terminal or command-line interface
- A text editor (vim, nano, VS Code, or any preferred editor)
- Basic understanding of command-line operations
Knowledge Prerequisites
- Familiarity with basic shell commands
- Understanding of variables in shell scripts
- Basic knowledge of file permissions and execution
- Comfort with terminal navigation
Setting Up Your Environment
Create a dedicated directory for practicing shell script conditionals:
```bash
mkdir ~/shell-conditionals
cd ~/shell-conditionals
```
Make sure your scripts are executable by setting appropriate permissions:
```bash
chmod +x script_name.sh
```
Understanding Shell Script Conditionals
Conditionals in shell scripts allow your programs to make decisions based on the evaluation of expressions or conditions. These constructs enable scripts to:
- Execute different code blocks based on user input
- Check file existence and properties
- Validate system states and configurations
- Handle errors and edge cases gracefully
- Create interactive and responsive automation scripts
Types of Conditionals
Shell scripts support several types of conditional constructs:
1. If statements - Basic conditional execution
2. If-else statements - Binary decision making
3. If-elif-else statements - Multiple condition handling
4. Case statements - Pattern matching and multi-way branching
5. Conditional operators - Inline conditional expressions
Basic If Statements
The if statement is the most fundamental conditional construct in shell scripting. It evaluates a condition and executes a block of code only if the condition is true.
Simple If Statement Syntax
```bash
if [ condition ]; then
# Commands to execute if condition is true
fi
```
Your First Conditional Script
Create a simple script that checks if a number is positive:
```bash
#!/bin/bash
number=10
if [ $number -gt 0 ]; then
echo "The number $number is positive"
fi
```
If-Else Statements
The if-else construct provides an alternative execution path when the condition is false:
```bash
#!/bin/bash
number=-5
if [ $number -gt 0 ]; then
echo "The number $number is positive"
else
echo "The number $number is not positive"
fi
```
If-Elif-Else Statements
For handling multiple conditions, use the elif (else if) construct:
```bash
#!/bin/bash
score=85
if [ $score -ge 90 ]; then
echo "Grade: A"
elif [ $score -ge 80 ]; then
echo "Grade: B"
elif [ $score -ge 70 ]; then
echo "Grade: C"
elif [ $score -ge 60 ]; then
echo "Grade: D"
else
echo "Grade: F"
fi
```
Test Operators and Conditions
Shell scripts provide various test operators for different types of comparisons and evaluations. Understanding these operators is crucial for writing effective conditionals.
Numeric Comparisons
Use these operators for comparing numbers:
| Operator | Description | Example |
|----------|-------------|---------|
| `-eq` | Equal to | `[ $a -eq $b ]` |
| `-ne` | Not equal to | `[ $a -ne $b ]` |
| `-lt` | Less than | `[ $a -lt $b ]` |
| `-le` | Less than or equal | `[ $a -le $b ]` |
| `-gt` | Greater than | `[ $a -gt $b ]` |
| `-ge` | Greater than or equal | `[ $a -ge $b ]` |
```bash
#!/bin/bash
num1=15
num2=20
if [ $num1 -lt $num2 ]; then
echo "$num1 is less than $num2"
fi
if [ $num1 -ne $num2 ]; then
echo "$num1 is not equal to $num2"
fi
```
String Comparisons
String comparison operators help evaluate text conditions:
| Operator | Description | Example |
|----------|-------------|---------|
| `=` or `==` | Equal to | `[ "$str1" = "$str2" ]` |
| `!=` | Not equal to | `[ "$str1" != "$str2" ]` |
| `<` | Less than (lexicographically) | `[[ "$str1" < "$str2" ]]` |
| `>` | Greater than (lexicographically) | `[[ "$str1" > "$str2" ]]` |
| `-z` | String is empty | `[ -z "$string" ]` |
| `-n` | String is not empty | `[ -n "$string" ]` |
```bash
#!/bin/bash
username="admin"
password=""
if [ "$username" = "admin" ]; then
echo "Username is correct"
fi
if [ -z "$password" ]; then
echo "Password is empty"
fi
```
File Test Operators
File test operators are essential for system administration scripts:
| Operator | Description | Example |
|----------|-------------|---------|
| `-e` | File exists | `[ -e "/path/file" ]` |
| `-f` | Regular file exists | `[ -f "/path/file" ]` |
| `-d` | Directory exists | `[ -d "/path/dir" ]` |
| `-r` | File is readable | `[ -r "/path/file" ]` |
| `-w` | File is writable | `[ -w "/path/file" ]` |
| `-x` | File is executable | `[ -x "/path/file" ]` |
| `-s` | File exists and is not empty | `[ -s "/path/file" ]` |
```bash
#!/bin/bash
config_file="/etc/nginx/nginx.conf"
if [ -f "$config_file" ]; then
echo "Configuration file exists"
if [ -r "$config_file" ]; then
echo "Configuration file is readable"
else
echo "Configuration file is not readable"
fi
else
echo "Configuration file does not exist"
fi
```
Advanced Conditional Structures
Double Bracket Syntax
The `[[ ]]` construct provides enhanced testing capabilities with additional features:
```bash
#!/bin/bash
string="Hello World"
Pattern matching
if [[ "$string" == "World" ]]; then
echo "String contains 'World'"
fi
Regular expressions
if [[ "$string" =~ ^Hello ]]; then
echo "String starts with 'Hello'"
fi
Multiple conditions without external operators
if [[ $number -gt 5 && $number -lt 15 ]]; then
echo "Number is between 5 and 15"
fi
```
Nested Conditionals
Complex decision trees often require nested conditional statements:
```bash
#!/bin/bash
user_type="admin"
user_active=true
permission_level=5
if [ "$user_type" = "admin" ]; then
echo "User is an administrator"
if [ "$user_active" = true ]; then
echo "Admin user is active"
if [ $permission_level -ge 5 ]; then
echo "Admin has full access"
else
echo "Admin has limited access"
fi
else
echo "Admin user is inactive"
fi
else
echo "User is not an administrator"
fi
```
Command Substitution in Conditionals
Use command output as conditional expressions:
```bash
#!/bin/bash
current_user=$(whoami)
disk_usage=$(df / | awk 'NR==2 {print $5}' | sed 's/%//')
if [ "$current_user" = "root" ]; then
echo "Running as root user"
fi
if [ $disk_usage -gt 80 ]; then
echo "Warning: Disk usage is above 80%"
echo "Current usage: ${disk_usage}%"
fi
```
Case Statements
Case statements provide an elegant way to handle multiple conditions based on pattern matching, making them ideal for menu systems and option processing.
Basic Case Statement Syntax
```bash
case $variable in
pattern1)
# Commands for pattern1
;;
pattern2)
# Commands for pattern2
;;
pattern3|pattern4)
# Commands for pattern3 or pattern4
;;
*)
# Default case
;;
esac
```
Practical Case Statement Example
```bash
#!/bin/bash
echo "Select an option:"
echo "1. Start service"
echo "2. Stop service"
echo "3. Restart service"
echo "4. Check status"
read -p "Enter your choice (1-4): " choice
case $choice in
1)
echo "Starting service..."
systemctl start nginx
;;
2)
echo "Stopping service..."
systemctl stop nginx
;;
3)
echo "Restarting service..."
systemctl restart nginx
;;
4)
echo "Checking service status..."
systemctl status nginx
;;
*)
echo "Invalid option. Please select 1-4."
exit 1
;;
esac
```
Advanced Case Patterns
Case statements support various pattern matching techniques:
```bash
#!/bin/bash
filename="$1"
case "$filename" in
*.txt)
echo "Text file detected"
;;
.jpg|.jpeg|.png|.gif)
echo "Image file detected"
;;
*.sh)
echo "Shell script detected"
if [ -x "$filename" ]; then
echo "Script is executable"
fi
;;
[Dd]ocument*)
echo "Document file starting with 'Document' or 'document'"
;;
*)
echo "Unknown file type"
;;
esac
```
Logical Operators
Logical operators allow you to combine multiple conditions for more complex decision-making.
AND Operator (&&)
```bash
#!/bin/bash
age=25
income=50000
Using && in if statement
if [ $age -ge 18 ] && [ $income -ge 30000 ]; then
echo "Eligible for loan"
fi
Using && with double brackets
if [[ $age -ge 18 && $income -ge 30000 ]]; then
echo "Eligible for loan (alternative syntax)"
fi
```
OR Operator (||)
```bash
#!/bin/bash
day="Saturday"
Using || in if statement
if [ "$day" = "Saturday" ] || [ "$day" = "Sunday" ]; then
echo "It's weekend!"
fi
Using || with double brackets
if [[ "$day" == "Saturday" || "$day" == "Sunday" ]]; then
echo "It's weekend! (alternative syntax)"
fi
```
NOT Operator (!)
```bash
#!/bin/bash
debug_mode=false
Using NOT operator
if [ ! "$debug_mode" = true ]; then
echo "Debug mode is disabled"
fi
Alternative NOT syntax
if ! [ "$debug_mode" = true ]; then
echo "Debug mode is disabled (alternative)"
fi
```
Complex Logical Expressions
```bash
#!/bin/bash
user="john"
role="admin"
login_attempts=2
max_attempts=3
if [[ ("$user" == "admin" || "$role" == "admin") && $login_attempts -lt $max_attempts ]]; then
echo "Access granted"
elif [[ $login_attempts -ge $max_attempts ]]; then
echo "Account locked due to too many failed attempts"
else
echo "Access denied"
fi
```
Practical Examples and Use Cases
System Monitoring Script
```bash
#!/bin/bash
System monitoring with conditionals
cpu_usage=$(top -bn1 | grep "Cpu(s)" | awk '{print $2}' | cut -d'%' -f1)
memory_usage=$(free | grep Mem | awk '{printf "%.0f", $3/$2 * 100.0}')
disk_usage=$(df / | awk 'NR==2 {print $5}' | sed 's/%//')
echo "=== System Monitoring Report ==="
CPU usage check
if (( $(echo "$cpu_usage > 80" | bc -l) )); then
echo "β οΈ HIGH CPU USAGE: ${cpu_usage}%"
elif (( $(echo "$cpu_usage > 50" | bc -l) )); then
echo "β‘ MODERATE CPU USAGE: ${cpu_usage}%"
else
echo "β
CPU USAGE NORMAL: ${cpu_usage}%"
fi
Memory usage check
if [ $memory_usage -gt 90 ]; then
echo "π΄ CRITICAL MEMORY USAGE: ${memory_usage}%"
elif [ $memory_usage -gt 70 ]; then
echo "π‘ HIGH MEMORY USAGE: ${memory_usage}%"
else
echo "β
MEMORY USAGE NORMAL: ${memory_usage}%"
fi
Disk usage check
if [ $disk_usage -gt 95 ]; then
echo "π΄ CRITICAL DISK USAGE: ${disk_usage}%"
echo "Immediate action required!"
elif [ $disk_usage -gt 80 ]; then
echo "π‘ HIGH DISK USAGE: ${disk_usage}%"
echo "Consider cleaning up files"
else
echo "β
DISK USAGE NORMAL: ${disk_usage}%"
fi
```
File Backup Script with Conditionals
```bash
#!/bin/bash
source_dir="/home/user/documents"
backup_dir="/backup"
date_stamp=$(date +%Y%m%d_%H%M%S)
Check if source directory exists
if [ ! -d "$source_dir" ]; then
echo "Error: Source directory $source_dir does not exist"
exit 1
fi
Check if backup directory exists, create if not
if [ ! -d "$backup_dir" ]; then
echo "Creating backup directory: $backup_dir"
mkdir -p "$backup_dir"
if [ $? -eq 0 ]; then
echo "Backup directory created successfully"
else
echo "Failed to create backup directory"
exit 1
fi
fi
Check available space
available_space=$(df "$backup_dir" | awk 'NR==2 {print $4}')
required_space=$(du -s "$source_dir" | awk '{print $1}')
if [ $available_space -lt $required_space ]; then
echo "Error: Insufficient space for backup"
echo "Required: ${required_space}KB, Available: ${available_space}KB"
exit 1
fi
Perform backup
backup_file="$backup_dir/backup_$date_stamp.tar.gz"
echo "Creating backup: $backup_file"
if tar -czf "$backup_file" -C "$(dirname "$source_dir")" "$(basename "$source_dir")"; then
echo "β
Backup completed successfully"
# Verify backup
if [ -f "$backup_file" ] && [ -s "$backup_file" ]; then
backup_size=$(ls -lh "$backup_file" | awk '{print $5}')
echo "Backup size: $backup_size"
else
echo "β οΈ Warning: Backup file appears to be empty or missing"
fi
else
echo "β Backup failed"
exit 1
fi
```
User Input Validation Script
```bash
#!/bin/bash
validate_email() {
local email=$1
local regex="^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$"
if [[ $email =~ $regex ]]; then
return 0
else
return 1
fi
}
validate_phone() {
local phone=$1
local regex="^[0-9]{10}$"
if [[ $phone =~ $regex ]]; then
return 0
else
return 1
fi
}
echo "User Registration Form"
echo "====================="
Name validation
while true; do
read -p "Enter your full name: " name
if [ -n "$name" ] && [[ "$name" =~ ^[a-zA-Z\ ]+$ ]]; then
break
else
echo "β Invalid name. Please use only letters and spaces."
fi
done
Email validation
while true; do
read -p "Enter your email: " email
if validate_email "$email"; then
break
else
echo "β Invalid email format. Please try again."
fi
done
Phone validation
while true; do
read -p "Enter your phone number (10 digits): " phone
if validate_phone "$phone"; then
break
else
echo "β Invalid phone number. Please enter 10 digits only."
fi
done
Age validation
while true; do
read -p "Enter your age: " age
if [[ "$age" =~ ^[0-9]+$ ]] && [ $age -ge 18 ] && [ $age -le 120 ]; then
break
else
echo "β Invalid age. Please enter a number between 18 and 120."
fi
done
echo ""
echo "β
Registration successful!"
echo "Name: $name"
echo "Email: $email"
echo "Phone: $phone"
echo "Age: $age"
```
Common Issues and Troubleshooting
Issue 1: Spacing in Conditional Statements
Problem: Syntax errors due to missing spaces around brackets.
```bash
β Incorrect - no spaces
if [$variable -eq 5]; then
β
Correct - proper spacing
if [ $variable -eq 5 ]; then
```
Solution: Always include spaces around brackets and operators.
Issue 2: Unquoted Variables
Problem: Variables containing spaces cause unexpected behavior.
```bash
β Problematic
filename="my file.txt"
if [ $filename = "my file.txt" ]; then # This will fail
β
Correct
if [ "$filename" = "my file.txt" ]; then # This works
```
Solution: Always quote variables in conditionals.
Issue 3: String vs Numeric Comparisons
Problem: Using wrong operators for different data types.
```bash
β Wrong - using string operator for numbers
if [ "10" > "5" ]; then # This compares lexicographically
β
Correct - using numeric operator
if [ 10 -gt 5 ]; then # This compares numerically
```
Solution: Use appropriate operators for the data type you're comparing.
Issue 4: Exit Status Confusion
Problem: Misunderstanding command exit status in conditionals.
```bash
Commands return 0 for success, non-zero for failure
if grep "pattern" file.txt; then
echo "Pattern found" # Executes if grep succeeds (returns 0)
fi
To check if pattern is NOT found:
if ! grep "pattern" file.txt; then
echo "Pattern not found"
fi
```
Issue 5: Case Statement Pattern Matching
Problem: Incorrect pattern syntax in case statements.
```bash
β Incorrect
case $var in
"option1") # Don't use quotes unless matching literal quotes
echo "Option 1"
;;
esac
β
Correct
case $var in
option1)
echo "Option 1"
;;
esac
```
Debugging Conditionals
Enable debugging to trace conditional execution:
```bash
#!/bin/bash
set -x # Enable debugging
Your conditional code here
if [ "$1" = "debug" ]; then
echo "Debug mode enabled"
fi
set +x # Disable debugging
```
Use verbose error checking:
```bash
#!/bin/bash
set -e # Exit on any error
set -u # Exit on undefined variables
set -o pipefail # Exit on pipe failures
Your script continues here
```
Best Practices and Professional Tips
1. Use Meaningful Variable Names
```bash
β Poor naming
if [ $u = "admin" ]; then
β
Good naming
if [ "$current_user" = "admin" ]; then
```
2. Implement Input Validation
```bash
#!/bin/bash
Always validate inputs
if [ $# -eq 0 ]; then
echo "Usage: $0 "
exit 1
fi
filename="$1"
if [ ! -f "$filename" ]; then
echo "Error: File '$filename' does not exist"
exit 1
fi
```
3. Use Functions for Complex Conditions
```bash
#!/bin/bash
is_valid_ip() {
local ip=$1
local regex="^([0-9]{1,3}\.){3}[0-9]{1,3}$"
if [[ $ip =~ $regex ]]; then
# Additional validation for range 0-255
IFS='.' read -ra ADDR <<< "$ip"
for i in "${ADDR[@]}"; do
if [ $i -gt 255 ]; then
return 1
fi
done
return 0
else
return 1
fi
}
Usage
read -p "Enter IP address: " ip_address
if is_valid_ip "$ip_address"; then
echo "Valid IP address"
else
echo "Invalid IP address"
fi
```
4. Handle Edge Cases
```bash
#!/bin/bash
process_file() {
local file="$1"
# Check if file parameter is provided
if [ -z "$file" ]; then
echo "Error: No file specified"
return 1
fi
# Check if file exists
if [ ! -e "$file" ]; then
echo "Error: File does not exist"
return 1
fi
# Check if it's actually a file
if [ ! -f "$file" ]; then
echo "Error: Not a regular file"
return 1
fi
# Check if file is readable
if [ ! -r "$file" ]; then
echo "Error: File is not readable"
return 1
fi
# Process the file
echo "Processing file: $file"
# Your file processing logic here
}
```
5. Use Consistent Formatting
```bash
#!/bin/bash
Consistent indentation and spacing
if [ condition1 ]; then
echo "Condition 1 met"
if [ condition2 ]; then
echo "Condition 2 also met"
else
echo "Condition 2 not met"
fi
elif [ condition3 ]; then
echo "Condition 3 met"
else
echo "No conditions met"
fi
```
6. Document Complex Conditionals
```bash
#!/bin/bash
Check if user has administrative privileges and system is not in maintenance mode
if [[ ("$USER" == "root" || $(groups "$USER" | grep -q "admin")) && ! -f "/var/maintenance.lock" ]]; then
echo "Administrative access granted"
# Perform administrative tasks
else
echo "Access denied: Insufficient privileges or system in maintenance"
fi
```
7. Use Configuration Files
```bash
#!/bin/bash
Load configuration
config_file="/etc/myapp/config.conf"
if [ -f "$config_file" ]; then
source "$config_file"
else
echo "Warning: Configuration file not found, using defaults"
MAX_RETRIES=3
TIMEOUT=30
fi
Use configuration in conditionals
if [ $retry_count -gt $MAX_RETRIES ]; then
echo "Maximum retries exceeded"
exit 1
fi
```
8. Implement Logging
```bash
#!/bin/bash
LOG_FILE="/var/log/myscript.log"
log_message() {
local level=$1
local message=$2
echo "$(date '+%Y-%m-%d %H:%M:%S') [$level] $message" >> "$LOG_FILE"
}
Use in conditionals
if [ ! -d "/backup" ]; then
log_message "ERROR" "Backup directory does not exist"
exit 1
else
log_message "INFO" "Backup directory found"
fi
```
Conclusion
Mastering conditionals in shell scripts is essential for creating robust, intelligent automation tools. Throughout this comprehensive guide, you've learned:
- Basic conditional structures including if, if-else, and if-elif-else statements
- Various test operators for numeric, string, and file comparisons
- Advanced techniques using double brackets and complex logical expressions
- Case statements for elegant multi-way branching
- Logical operators for combining multiple conditions
- Practical applications through real-world examples
- Troubleshooting techniques for common issues
- Best practices for writing maintainable and reliable scripts
Key Takeaways
1. Always quote variables in conditional expressions to handle spaces and special characters properly
2. Use appropriate operators for different data types (numeric vs string comparisons)
3. Implement proper error handling and input validation in your scripts
4. Follow consistent formatting and naming conventions for better readability
5. Test edge cases and handle unexpected scenarios gracefully
6. Document complex conditionals to make your scripts maintainable
Next Steps
Now that you have a solid foundation in shell script conditionals, consider exploring these advanced topics:
- Loop constructs (for, while, until) combined with conditionals
- Function development with conditional logic
- Error handling patterns and exception management
- Advanced pattern matching and regular expressions
- Performance optimization for conditional-heavy scripts
- Cross-platform compatibility considerations
Practice Recommendations
To reinforce your learning:
1. Create a system administration toolkit using various conditional structures
2. Build interactive menu systems with case statements
3. Develop file processing scripts with comprehensive validation
4. Practice debugging techniques with complex conditional logic
5. Contribute to open-source shell script projects to see real-world implementations
Remember that effective use of conditionals is not just about syntaxβit's about creating logical, maintainable, and reliable automation solutions. Start with simple conditions and gradually build complexity as you become more comfortable with these powerful constructs.
The skills you've gained from this guide will serve as a foundation for advanced shell scripting techniques and will help you create more sophisticated automation tools for system administration, DevOps, and general computing tasks.