Control Flow
Master conditional statements and loops in Bash. This page will also introduce you to Regular Expressions in Bash.
If Statements
Conditional execution based on test conditions:
#!/bin/bash
# Basic if statement
if [ $age -ge 18 ]; then
echo "Adult"
fi
# If-else
if [ $score -ge 60 ]; then
echo "Pass"
else
echo "Fail"
fi
# If-elif-else
if [ $grade -ge 90 ]; then
echo "A"
elif [ $grade -ge 80 ]; then
echo "B"
elif [ $grade -ge 70 ]; then
echo "C"
else
echo "F"
fi
[ $var -eq 5 ] not [$var -eq 5]
Test Operators
Integer Comparisons
-eq # Equal to
-ne # Not equal to
-gt # Greater than
-lt # Less than
-ge # Greater than or equal to
-le # Less than or equal to
# Examples
[ $a -eq $b ] # Is a equal to b?
[ $x -gt 10 ] # Is x greater than 10?
String Comparisons
= # Equal to
!= # Not equal to
-z # String is empty
-n # String is not empty
< # Less than (alphabetically)
> # Greater than (alphabetically)
# Examples
[ "$str1" = "$str2" ] # Are strings equal?
[ -z "$str" ] # Is string empty?
[ -n "$str" ] # Is string not empty?
File Tests
-e # File exists
-f # Is a regular file
-d # Is a directory
-r # File is readable
-w # File is writable
-x # File is executable
-s # File is not empty
# Examples
if [ -f "config.txt" ]; then
echo "Config file exists"
fi
if [ -d "/var/log" ]; then
echo "Directory exists"
fi
if [ ! -e "file.txt" ]; then
echo "File does not exist"
fi
Logical Operators
&& # AND
|| # OR
! # NOT
# Examples
if [ $age -ge 18 ] && [ $age -le 65 ]; then
echo "Working age"
fi
if [ $x -lt 0 ] || [ $x -gt 100 ]; then
echo "Out of range"
fi
if [ ! -d "backup" ]; then
mkdir backup
fi
Modern Test Syntax [[ ]]
The double bracket syntax provides more features and is generally preferred:
# Pattern matching
if [[ $filename == *.txt ]]; then
echo "Text file"
fi
# Regular expressions
if [[ $email =~ ^[a-zA-Z0-9]+@[a-zA-Z0-9]+\.[a-zA-Z]{2,}$ ]]; then
echo "Valid email format"
fi
# No word splitting (safer)
if [[ $var == "hello world" ]]; then
echo "Match"
fi
# Logical operators (easier to read)
if [[ $age -ge 18 && $citizen == "yes" ]]; then
echo "Can vote"
fi
Case Statements
Multi-way branching for cleaner code:
#!/bin/bash
read -p "Enter a letter: " letter
case $letter in
[aeiou])
echo "Vowel"
;;
[0-9])
echo "Digit"
;;
[A-Z])
echo "Uppercase letter"
;;
*)
echo "Other character"
;;
esac
#!/bin/bash
# Menu system
echo "Select an option:"
echo "1) Start service"
echo "2) Stop service"
echo "3) Restart service"
echo "4) Exit"
read -p "Choice: " choice
case $choice in
1|start)
echo "Starting service..."
;;
2|stop)
echo "Stopping service..."
;;
3|restart)
echo "Restarting service..."
;;
4|exit|quit)
echo "Goodbye!"
exit 0
;;
*)
echo "Invalid option"
exit 1
;;
esac
For Loops
Basic For Loop
# Loop over a list
for item in apple banana cherry; do
echo "Fruit: $item"
done
# Loop over command output
for file in *.txt; do
echo "Processing $file"
cat "$file"
done
# Loop over array
fruits=("apple" "banana" "cherry")
for fruit in "${fruits[@]}"; do
echo "$fruit"
done
C-Style For Loop
# Traditional for loop
for ((i=0; i<10; i++)); do
echo "Number: $i"
done
# Countdown
for ((i=10; i>=1; i--)); do
echo "$i"
sleep 1
done
echo "Liftoff!"
Looping Through Files
# Safe way to loop through files with spaces
while IFS= read -r -d '' file; do
echo "Found: $file"
done < <(find . -name "*.log" -print0)
# Simple file loop
for file in /var/log/*.log; do
if [ -f "$file" ]; then
echo "Log file: $file"
fi
done
While Loops
Execute commands while a condition is true:
# Basic while loop
counter=1
while [ $counter -le 5 ]; do
echo "Count: $counter"
((counter++))
done
# Read file line by line
while IFS= read -r line; do
echo "Line: $line"
done < input.txt
# Infinite loop with break
while true; do
read -p "Enter command (quit to exit): " cmd
if [ "$cmd" = "quit" ]; then
break
fi
echo "You entered: $cmd"
done
#!/bin/bash
# Wait for file to appear
echo "Waiting for file.txt..."
while [ ! -f "file.txt" ]; do
sleep 1
echo "Still waiting..."
done
echo "File found!"
Until Loops
Execute commands until a condition becomes true:
# Basic until loop (opposite of while)
counter=1
until [ $counter -gt 5 ]; do
echo "Count: $counter"
((counter++))
done
# Wait until service is ready
until curl -s http://localhost:8080 > /dev/null; do
echo "Waiting for service..."
sleep 2
done
echo "Service is ready!"
Loop Control
# break - exit the loop
for i in {1..10}; do
if [ $i -eq 5 ]; then
break # Exit loop when i is 5
fi
echo $i
done
# continue - skip to next iteration
for i in {1..10}; do
if [ $((i % 2)) -eq 0 ]; then
continue # Skip even numbers
fi
echo $i # Only prints odd numbers
done
# Nested loops with break
for i in {1..3}; do
for j in {1..3}; do
if [ $j -eq 2 ]; then
break # Only breaks inner loop
fi
echo "$i,$j"
done
done
Select Menu
Create interactive menus easily:
#!/bin/bash
echo "Choose your favorite fruit:"
select fruit in "Apple" "Banana" "Cherry" "Quit"; do
case $fruit in
"Apple")
echo "You chose Apple"
;;
"Banana")
echo "You chose Banana"
;;
"Cherry")
echo "You chose Cherry"
;;
"Quit")
echo "Goodbye!"
break
;;
*)
echo "Invalid option $REPLY"
;;
esac
done
1. What is a Regular Expression (regex)?
A regular expression is a sequence of characters that forms a search pattern, commonly used for string matching, extraction, and text validation.
2. Regex in Bash Scripting
- Bash supports regex in the
[[ string =~ regex ]]conditional expression. - Regex is also widely used in tools like
grep,sed,awk.
=~, similar to egrep.
3. Basic Syntax Examples
-
In Bash conditionals:
text="hello2024" if [[ $text =~ [a-z]+[0-9]+ ]]; then echo "It matches!" fi -
With
grep:grep "^[A-Z][a-z]+" names.txt
4. Common Regex Patterns
| Pattern | Meaning |
|---|---|
. | Any single character |
[abc] | Any character a, b, or c |
[^abc] | Any character NOT a, b, or c |
[a-z] | Any lowercase letter |
[0-9] | Any digit |
+ | One or more (e.g., ab+ matches ab, abb, abbb) |
* | Zero or more |
? | Zero or one |
^ | Start of line |
$ | End of line |
(...) | Capture group |
| | Or (alternation) |
5. Practical Bash Regex Matching Example
#!/bin/bash
email="test@linux.org"
pattern='^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$'
if [[ $email =~ $pattern ]]; then
echo "Valid email address"
else
echo "Invalid email"
fi
- Double brackets
[[ ... ]]required for regex matching. - No need to quote the pattern variable with
=~.
6. Regex with grep and sed
-
Search lines containing a phone number:
grep -E '[0-9]{3}-[0-9]{3}-[0-9]{4}' contacts.txt -
Replace digits with "X" in a file:
sed -E 's/[0-9]/X/g' secret.txt
7. Extracting regex matches in Bash
line="My phone: 555-1212"
if [[ $line =~ ([0-9]{3})-([0-9]{4}) ]]; then
echo "Area: ${BASH_REMATCH[1]}, Number: ${BASH_REMATCH[2]}"
fi
BASH_REMATCHcontains matched substrings and capture groups.
8. Perl and Python One-Liners for Bash Scripting
Perl and Python one-liners are powerful tools for manipulating text, processing data, and performing quick operations directly from the command line, often used as part of Bash scripts. Here are some useful examples to help streamline your workflow:
Perl One-Liners
- Print only lines matching a pattern:
perl -ne 'print if /pattern/' filename - Replace text in a file (in-place):
perl -pi -e 's/old/new/g' filename - Print line numbers with lines:
perl -ne 'print "$. $_"' filename - Sum numbers in a column:
perl -lane '$sum += $F[0]; END { print $sum }' filename
Python One-Liners
- Print lines containing a pattern:
python3 -c "import sys; [print(line, end='') for line in sys.stdin if 'pattern' in line]" < filename - Replace text in a file (output to stdout):
python3 -c "import sys; [print(line.replace('old','new'), end='') for line in sys.stdin]" < filename - Count unique lines:
python3 -c "import sys; print(len(set(sys.stdin)))" < filename - Sum numbers in a column:
python3 -c "import sys; print(sum(float(line.split()[0]) for line in sys.stdin))" < filename
These one-liners can be embedded directly within Bash scripts or used in pipelines to process data efficiently. Be sure to adjust patterns and column indices to suit your specific use cases.