Shell Script Conditionals: Complete Guide with Examples

Master shell script conditionals with this comprehensive guide covering if statements, test operators, and advanced constructs for bash scripting.

Shell Script Conditionals: Complete Guide

Table of Contents

1. [Introduction to Conditionals](#introduction-to-conditionals) 2. [Basic Conditional Syntax](#basic-conditional-syntax) 3. [Test Commands and Operators](#test-commands-and-operators) 4. [Conditional Statements](#conditional-statements) 5. [Advanced Conditional Constructs](#advanced-conditional-constructs) 6. [Best Practices](#best-practices) 7. [Common Use Cases](#common-use-cases) 8. [Troubleshooting](#troubleshooting)

Introduction to Conditionals

Conditionals in shell scripts are fundamental constructs that allow scripts to make decisions based on various conditions. They enable programs to execute different code paths depending on the evaluation of expressions, file states, variable values, or command exit statuses. Shell conditionals form the backbone of logic flow control in bash scripting.

The shell provides several mechanisms for implementing conditional logic, including the if statement, case statement, and logical operators. These constructs work by evaluating test conditions that return either true (exit status 0) or false (non-zero exit status).

Basic Conditional Syntax

The if Statement Structure

The basic if statement in shell scripting follows this syntax:

`bash if [ condition ]; then # commands to execute if condition is true fi `

The extended form includes else and elif clauses:

`bash if [ condition1 ]; then # commands for condition1 elif [ condition2 ]; then # commands for condition2 else # commands if no conditions are true fi `

Command Notes

- The [ is actually a command (alias for test) - Spaces around brackets are mandatory - The then keyword can be on the same line with a semicolon or on a new line - Each if must have a corresponding fi - The elif clause allows multiple condition testing

Test Commands and Operators

File Test Operators

File test operators check various properties of files and directories:

| 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 ] | | -L | File is a symbolic link | [ -L /path/link ] | | -O | File is owned by current user | [ -O /path/file ] | | -G | File group matches current user | [ -G /path/file ] |

String Comparison Operators

String operators compare text values and check string properties:

| Operator | Description | Example | |----------|-------------|---------| | = or == | Strings are equal | [ "$str1" = "$str2" ] | | != | Strings are not equal | [ "$str1" != "$str2" ] | | < | String1 is less than string2 | [ "$str1" \< "$str2" ] | | > | String1 is greater than string2 | [ "$str1" \> "$str2" ] | | -z | String is empty | [ -z "$string" ] | | -n | String is not empty | [ -n "$string" ] |

Numeric Comparison Operators

Numeric operators perform mathematical comparisons:

| Operator | Description | Example | |----------|-------------|---------| | -eq | Equal to | [ $num1 -eq $num2 ] | | -ne | Not equal to | [ $num1 -ne $num2 ] | | -lt | Less than | [ $num1 -lt $num2 ] | | -le | Less than or equal | [ $num1 -le $num2 ] | | -gt | Greater than | [ $num1 -gt $num2 ] | | -ge | Greater than or equal | [ $num1 -ge $num2 ] |

Logical Operators

Logical operators combine multiple conditions:

| Operator | Description | Example | |----------|-------------|---------| | && | Logical AND | [ condition1 ] && [ condition2 ] | | \|\| | Logical OR | [ condition1 ] \|\| [ condition2 ] | | ! | Logical NOT | [ ! condition ] | | -a | AND (within test) | [ condition1 -a condition2 ] | | -o | OR (within test) | [ condition1 -o condition2 ] |

Conditional Statements

Basic if-then-else Examples

Here are practical examples demonstrating various conditional constructs:

`bash #!/bin/bash

Simple file existence check

if [ -f "/etc/passwd" ]; then echo "Password file exists" else echo "Password file not found" fi

Multiple conditions with elif

read -p "Enter your age: " age

if [ $age -lt 13 ]; then echo "You are a child" elif [ $age -lt 20 ]; then echo "You are a teenager" elif [ $age -lt 60 ]; then echo "You are an adult" else echo "You are a senior" fi

String comparison

read -p "Enter your name: " username

if [ "$username" = "admin" ]; then echo "Welcome administrator" elif [ -z "$username" ]; then echo "No username provided" else echo "Hello $username" fi `

Complex Conditional Logic

`bash #!/bin/bash

File permission and existence check

filename="/path/to/file"

if [ -e "$filename" ]; then if [ -r "$filename" ] && [ -w "$filename" ]; then echo "File exists and is readable and writable" elif [ -r "$filename" ]; then echo "File exists and is readable only" else echo "File exists but no read permissions" fi else echo "File does not exist" fi

Combining multiple test conditions

user_input="test" number=42

if [ -n "$user_input" ] && [ $number -gt 40 ]; then echo "Both conditions are true" fi

Using logical NOT

if [ ! -d "/nonexistent" ]; then echo "Directory does not exist" fi `

Case Statement

The case statement provides an alternative to multiple elif conditions:

`bash #!/bin/bash

read -p "Enter a letter: " letter

case $letter in [aeiou]|[AEIOU]) echo "You entered a vowel" ;; [0-9]) echo "You entered a number" ;; [a-zA-Z]) echo "You entered a consonant" ;; *) echo "You entered a special character" ;; esac `

Case Statement Patterns

| Pattern Type | Example | Description | |--------------|---------|-------------| | Literal | "hello") | Exact string match | | Wildcard | *.txt) | Pattern matching | | Character class | [0-9]) | Range of characters | | Multiple patterns | yes\|y\|Y) | OR conditions | | Default | *) | Catch-all pattern |

Advanced Conditional Constructs

Double Bracket Syntax

The [[ construct provides enhanced conditional testing:

`bash #!/bin/bash

Pattern matching with double brackets

string="hello world"

if [[ $string == "world" ]]; then echo "String contains 'world'" fi

Regular expression matching

if [[ $string =~ ^hello ]]; then echo "String starts with 'hello'" fi

Empty variable check without quotes

if [[ -z $variable ]]; then echo "Variable is empty" fi `

Arithmetic Evaluation

Using (( for arithmetic conditions:

`bash #!/bin/bash

num1=10 num2=20

Arithmetic comparison

if (( num1 < num2 )); then echo "$num1 is less than $num2" fi

Complex arithmetic

if (( (num1 + num2) > 25 )); then echo "Sum is greater than 25" fi

Increment and test

counter=0 if (( ++counter == 1 )); then echo "Counter incremented to 1" fi `

Conditional Assignment

`bash #!/bin/bash

Default value assignment

username=${1:-"anonymous"} echo "Username: $username"

Conditional variable setting

debug_mode=${DEBUG:-false}

if [ "$debug_mode" = "true" ]; then echo "Debug mode enabled" fi

Parameter expansion with conditions

config_file=${CONFIG_FILE:="/etc/default.conf"} echo "Using config file: $config_file" `

Short-Circuit Evaluation

`bash #!/bin/bash

Command execution based on conditions

[ -f "important.txt" ] && echo "File found" || echo "File missing"

Create directory if it doesn't exist

[ ! -d "logs" ] && mkdir logs

Backup file if it exists

[ -f "data.txt" ] && cp data.txt data.txt.backup

Chain multiple commands

[ -x "/usr/bin/git" ] && [ -d ".git" ] && echo "Git repository detected" `

Best Practices

Quoting Variables

Always quote variables to prevent word splitting and pathname expansion:

`bash

Correct

if [ "$variable" = "value" ]; then echo "Match found" fi

Incorrect - may fail with spaces in variable

if [ $variable = "value" ]; then echo "This might fail" fi `

Error Handling

`bash #!/bin/bash

Check command line arguments

if [ $# -eq 0 ]; then echo "Usage: $0 " exit 1 fi

filename="$1"

Validate file before processing

if [ ! -f "$filename" ]; then echo "Error: File '$filename' not found" exit 1 fi

if [ ! -r "$filename" ]; then echo "Error: Cannot read file '$filename'" exit 1 fi

echo "Processing file: $filename" `

Performance Considerations

`bash #!/bin/bash

Use double brackets for better performance

if [[ -f "$file" && -r "$file" ]]; then # Process file cat "$file" fi

Avoid unnecessary subprocess calls

Instead of: if [ $(wc -l < file) -gt 100 ]

Use: if [[ $(wc -l < file) -gt 100 ]]

Cache expensive operations

file_count=$(find /path -type f | wc -l) if [[ $file_count -gt 1000 ]]; then echo "Many files found: $file_count" fi `

Common Use Cases

System Administration Scripts

`bash #!/bin/bash

Disk space monitoring

threshold=90 usage=$(df / | awk 'NR==2 {print $5}' | sed 's/%//')

if [ $usage -gt $threshold ]; then echo "WARNING: Disk usage is ${usage}%" # Send alert or cleanup fi

Service status check

if systemctl is-active --quiet nginx; then echo "Nginx is running" else echo "Starting nginx service" systemctl start nginx fi

Log file rotation

log_file="/var/log/application.log" max_size=10485760 # 10MB

if [ -f "$log_file" ] && [ $(stat -f%z "$log_file" 2>/dev/null || stat -c%s "$log_file") -gt $max_size ]; then mv "$log_file" "${log_file}.old" touch "$log_file" echo "Log file rotated" fi `

User Input Validation

`bash #!/bin/bash

validate_email() { local email="$1" if [[ $email =~ ^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$ ]]; then return 0 else return 1 fi }

read -p "Enter your email: " user_email

if validate_email "$user_email"; then echo "Valid email address" else echo "Invalid email format" exit 1 fi

Numeric input validation

read -p "Enter a number between 1 and 100: " number

if ! [[ "$number" =~ ^[0-9]+$ ]]; then echo "Error: Not a valid number" exit 1 elif [ $number -lt 1 ] || [ $number -gt 100 ]; then echo "Error: Number out of range" exit 1 else echo "Valid number: $number" fi `

Configuration Management

`bash #!/bin/bash

config_file="/etc/myapp/config.conf" backup_dir="/etc/myapp/backups"

Ensure backup directory exists

if [ ! -d "$backup_dir" ]; then mkdir -p "$backup_dir" fi

Backup existing config

if [ -f "$config_file" ]; then timestamp=$(date +%Y%m%d_%H%M%S) cp "$config_file" "$backup_dir/config.conf.$timestamp" echo "Configuration backed up" fi

Validate new configuration

validate_config() { local config="$1" if [ ! -f "$config" ]; then echo "Config file not found" return 1 fi # Check for required parameters if ! grep -q "^database_host=" "$config"; then echo "Missing database_host parameter" return 1 fi return 0 }

new_config="$1" if [ -z "$new_config" ]; then echo "Usage: $0 " exit 1 fi

if validate_config "$new_config"; then cp "$new_config" "$config_file" echo "Configuration updated successfully" else echo "Configuration validation failed" exit 1 fi `

Troubleshooting

Common Errors and Solutions

| Error | Cause | Solution | |-------|-------|----------| | [: missing ] | Missing closing bracket | Add closing bracket with proper spacing | | [: too many arguments | Unquoted variable with spaces | Quote the variable: "$var" | | command not found: [[ | Using [[ in non-bash shell | Use [ or ensure bash interpreter | | integer expression expected | Non-numeric comparison with numeric operators | Validate input or use string operators |

Debugging Conditionals

`bash #!/bin/bash

Enable debug mode

set -x

Test variable content

variable="test value" echo "Variable contains: '$variable'" echo "Variable length: ${#variable}"

Test condition step by step

if [ -n "$variable" ]; then echo "Variable is not empty" fi

Disable debug mode

set +x

Manual debugging

debug=true if [ "$debug" = "true" ]; then echo "Debug: Testing file existence" ls -la "$filename" 2>/dev/null || echo "File not accessible" fi `

Testing Conditionals

`bash #!/bin/bash

Function to test conditions

test_condition() { local description="$1" local condition="$2" echo -n "Testing: $description ... " if eval "$condition"; then echo "PASS" else echo "FAIL" fi }

Run tests

test_condition "File exists" "[ -f '/etc/passwd' ]" test_condition "Number comparison" "[ 10 -gt 5 ]" test_condition "String equality" "[ 'hello' = 'hello' ]" test_condition "Variable is set" "[ -n '$HOME' ]" `

Performance Testing

`bash #!/bin/bash

Benchmark different conditional approaches

time_test() { local description="$1" local command="$2" local iterations=10000 echo "Testing: $description" time for ((i=0; i/dev/null done echo }

Compare single vs double brackets

time_test "Single brackets" '[ -f "/etc/passwd" ]' time_test "Double brackets" '[[ -f "/etc/passwd" ]]'

Compare different string tests

string="test" time_test "String length with -n" '[ -n "$string" ]' time_test "String length with test" '[ ${#string} -gt 0 ]' `

This comprehensive guide covers the essential aspects of using conditionals in shell scripts, from basic syntax to advanced techniques and real-world applications. The examples and explanations provide a solid foundation for implementing robust conditional logic in bash scripting environments.

Tags

  • Linux
  • Programming
  • bash
  • conditionals
  • shell-scripting

Related Articles

Popular Technical Articles & Tutorials

Explore our comprehensive collection of technical articles, programming tutorials, and IT guides written by industry experts:

Browse all 8+ technical articles | Read our IT blog

Shell Script Conditionals: Complete Guide with Examples