6.4. Expressions in Conditionals#

Now that you understand operators, let’s put them to work in if statements, loops, and logic. This is where operators become the decision-makers in your scripts.

6.4.1. Real-World Script: File Processor#

Complete example combining all operators:

#!/bin/bash

# Validate input
[ -z "$1" ] && {
  echo "Usage: $0 <filename>"
  exit 1
}

file="$1"

# Check if file exists and is readable
[ ! -f "$file" ] && {
  echo "Error: '$file' is not a file"
  exit 1
}

[ ! -r "$file" ] && {
  echo "Error: '$file' is not readable"
  exit 1
}

# Process file
echo "Processing file: $file"
line_count=0

while IFS= read -r line; do
  [ -z "$line" ] && continue      # Skip empty lines
  
  ((line_count++))
  
  # Check for errors
  if [[ "$line" =~ ERROR ]]; then
    echo "Line $line_count (ERROR): $line"
  elif [[ "$line" =~ WARNING ]]; then
    echo "Line $line_count (WARN): $line"
  fi
done < "$file"

echo "Processed $line_count non-empty lines"

6.4.1.1. && and || Together: if/else Pattern#

# Run first_command if condition true, else second_command
[ condition ] && first_command || second_command

# Example: copy or warn
[ -f "$source" ] && cp "$source" "$dest" || echo "Source not found"

# Example: grant or deny
[ "$user" = "admin" ] && echo "Welcome!" || echo "Access denied"

Warning: This pattern can fail if first_command fails! Better:

# More robust:
if [ condition ]; then
  first_command
else
  second_command
fi

6.4.1.2. || Operator: Run if Failed#

# Run command2 only if command1 fails
command1 || command2

# Example: Create dir if it doesn't exist
[ -d "$dir" ] || mkdir -p "$dir"

# Example: Default value
user=${1:-"nobody"}  # Use $1, default to "nobody"

# Common pattern: exit if check fails
[ -f "$config" ] || { echo "Config not found"; exit 1; }

6.4.1.3. && Operator: Run if Successful#

# Run command2 only if command1 succeeds
command1 && command2

# Example: Create directory and enter it
mkdir -p /tmp/mydir && cd /tmp/mydir

# Example: Run test only if file exists
[ -f config.sh ] && source config.sh

# Multiple commands
[ -w "$file" ] && echo "Backing up..." && cp "$file" "$file.bak"

6.4.2. Conditional Expressions with && and ||#

Shorthand for if/else logic:

6.4.2.1. continue: Skip to Next Iteration#

for i in {1..5}; do
  if [ $i -eq 3 ]; then
    echo "Skipping 3"
    continue
  fi
  echo "Number: $i"
done

Output:

Number: 1
Number: 2
Skipping 3
Number: 4
Number: 5

Real example: skip empty lines

#!/bin/bash

while IFS= read -r line; do
  [ -z "$line" ] && continue  # Skip empty lines
  echo "Processing: $line"
done < "input.txt"

6.4.2.2. break: Exit Loop Early#

for i in {1..10}; do
  if [ $i -eq 5 ]; then
    echo "Found 5, breaking"
    break
  fi
  echo "Number: $i"
done

echo "Done"

Output:

Number: 1
Number: 2
Number: 3
Number: 4
Found 5, breaking
Done

Real example: search for file

#!/bin/bash

for file in *.log; do
  if grep -q "ERROR" "$file"; then
    echo "Found error in $file"
    break  # Stop searching after first error file found
  fi
done

6.4.3. break and continue#

Control loop flow:

6.4.3.1. for Loop: C-Style#

for (( i=start; i<end; i++ )); do
  echo "Iteration $i"
done

Real example: number sequence

#!/bin/bash

for (( i=1; i<=10; i++ )); do
  echo "Number: $i"
done

Real example: backwards loop

#!/bin/bash

for (( i=10; i>0; i-- )); do
  echo "$i seconds remaining..."
  sleep 1
done

Comparison:

  • for var in list → Iterate over items

  • for (( i=0; i<10; i++ )) → C-style loop with counter

6.4.3.2. for Loop: Iterate Over List#

for var in item1 item2 item3; do
  echo "Processing: $var"
done

Real example: process files

#!/bin/bash

for file in *.txt; do
  echo "Found: $file"
  wc -l "$file"
done

Real example: command output

#!/bin/bash

for user in $(cat /etc/passwd | cut -d: -f1); do
  echo "User: $user"
done

6.4.4. for Loops#

Three ways to loop in bash:

6.4.4.1. until Loop#

Execute until condition becomes true (opposite of while):

until [ condition ]; do
  # code runs until condition becomes true
done

Real example:

#!/bin/bash
# Keep trying to connect until success

until ping -c 1 8.8.8.8 &>/dev/null; do
  echo "Waiting for internet..."
  sleep 2
done

echo "Connected!"

Comparison:

  • while [ $x -lt 10 ] → Loop while x < 10 (stop when x >= 10)

  • until [ $x -ge 10 ] → Loop until x >= 10 (same effect!)

6.4.4.2. while Loop#

Execute while condition is true:

while [ condition ]; do
  # code runs as long as condition is true
done

Real example: countdown

#!/bin/bash
count=5

while [ $count -gt 0 ]; do
  echo "$count..."
  ((count--))
done

echo "Blastoff!"

Real example: read until empty

#!/bin/bash

while [ -z "$input" ]; do
  read -p "Enter something: " input
  [ -z "$input" ] && echo "Can't be empty!"
done

echo "You entered: $input"

6.4.5. while and until Loops#

Loop while (or until) conditions are true:

6.4.5.1. if/elif/else Statement#

Test multiple conditions in sequence:

if [ condition1 ]; then
  echo "condition1 was true"
elif [ condition2 ]; then
  echo "condition1 was false, condition2 was true"
elif [ condition3 ]; then
  echo "conditions 1 and 2 were false, condition3 is true"
else
  echo "all conditions were false"
fi

Real example:

#!/bin/bash
score=$1

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

6.4.5.2. if/else Statement#

if [ condition ]; then
  echo "condition was true"
else
  echo "condition was false"
fi

Real example:

#!/bin/bash
password="$1"

if [ "$password" = "secret" ]; then
  echo "Access granted"
else
  echo "Access denied"
fi

6.4.5.3. Basic if Statement#

if [ condition ]; then
  # code executes if condition is true
  echo "condition was true"
fi

Real example:

#!/bin/bash
age=20

if [ $age -ge 18 ]; then
  echo "You are an adult"
fi

6.4.6. if/else Statements#

The basic decision structure: