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.