Skip to main content

Bash Fundamentals

Master the core concepts of Bash scripting including variables, control structures, functions, and data types.

Getting Started

Hello World

#!/bin/bash
echo "Hello, World!"

Save as hello.sh, then:

chmod +x hello.sh
./hello.sh

Variables

Bash uses dynamic typing. Assign values without declaring types:

name="Alice"
age=30
path="/home/user"

Retrieve variables with $:

echo $name
echo ${name} # Explicit braces (safer)
echo "${name}" # With quotes (prevents word splitting)

Variable Naming Rules:

  • Start with letter or underscore
  • Contain letters, numbers, underscores
  • Case-sensitive (Namename)

Quoting

Quoting prevents word splitting, globbing, and variable expansion in different ways:

Double Quotes — Allow variable and command expansion:

greeting="Hello, $name"
echo "$greeting" # Expands $name

Single Quotes — Literal strings (no expansion):

path='$HOME/docs'
echo "$path" # Outputs: $HOME/docs

Escape Character — Backslash escapes special characters:

echo "He said \"Hello\""   # Outputs: He said "Hello"
echo "Price: \$100" # Outputs: Price: $100

No Quotes — Subject to word splitting and globbing:

files=*.txt       # Expands to all .txt files

Command Substitution

Capture command output into variables:

current_user=$(whoami)
host=$(hostname)
current_date=`date +%Y-%m-%d` # Backticks (older syntax)

Data Types & Operations

Arrays

Indexed Arrays:

colors=("red" "green" "blue")
colors[3]="yellow"
echo ${colors[0]} # red
echo ${colors[@]} # All elements
echo ${#colors[@]} # Array length

Looping Through Arrays:

for color in "${colors[@]}"; do
echo "Color: $color"
done

Unset Array Elements:

unset colors[1]           # Remove green
unset colors # Remove entire array

Associative Arrays

Key-value pairs (Bash 4+):

declare -A person
person[name]="Alice"
person[age]="30"
person[city]="New York"

echo ${person[name]} # Alice
echo ${!person[@]} # Keys: name age city
echo ${person[@]} # Values: Alice 30 New York

String Manipulation

Length:

str="hello"
echo ${#str} # 5

Substring:

str="Hello, World!"
echo ${str:0:5} # Hello (offset 0, length 5)
echo ${str:7} # World! (from position 7)

Parameter Expansion (Remove/Replace):

filename="document.txt"
echo ${filename%.txt} # document (remove suffix)
echo ${filename#*o} # document.txt (remove prefix up to 'o')

text="foo bar foo"
echo ${text/foo/FOO} # FOO bar foo (replace first)
echo ${text//foo/FOO} # FOO bar FOO (replace all)

Arithmetic

Using $(( )):

result=$((5 + 3))
echo $result # 8

x=10
y=3
echo $((x * y)) # 30
echo $((x / y)) # 3
echo $((x % y)) # 1
echo $((x ** 2)) # 100 (exponentiation)

Increment/Decrement:

count=0
((count++))
((count+=5))
echo $count # 6

Using let:

let result=5+3
let x+=10

Control Structures

If/Else

if [ "$age" -gt 18 ]; then
echo "Adult"
elif [ "$age" -gt 12 ]; then
echo "Teenager"
else
echo "Child"
fi

Test Operators:

OperatorMeaning
-eqEqual
-neNot equal
-ltLess than
-leLess than or equal
-gtGreater than
-geGreater than or equal
-zString is empty
-nString is not empty
=Strings equal
!=Strings not equal
-fFile exists and is regular file
-dDirectory exists
-eFile/dir exists
-rFile is readable
-wFile is writable
-xFile is executable

Logical Operators:

if [ "$age" -gt 18 ] && [ "$age" -lt 65 ]; then
echo "Working age"
fi

if [ "$role" = "admin" ] || [ "$role" = "root" ]; then
echo "Has privileges"
fi

if [ ! -f "$file" ]; then
echo "File does not exist"
fi

For Loop

Iterate over list:

for item in apple banana cherry; do
echo "Fruit: $item"
done

Iterate over range:

for i in {1..5}; do
echo "Number: $i"
done

C-style for loop:

for ((i=0; i<5; i++)); do
echo "Count: $i"
done

Iterate over array:

files=("file1.txt" "file2.txt" "file3.txt")
for file in "${files[@]}"; do
echo "Processing: $file"
done

While Loop

counter=0
while [ $counter -lt 5 ]; do
echo "Counter: $counter"
((counter++))
done

Read input line-by-line:

while IFS= read -r line; do
echo "Line: $line"
done < file.txt

Case Statement

case "$1" in
start)
echo "Starting service..."
;;
stop)
echo "Stopping service..."
;;
restart)
echo "Restarting service..."
;;
*)
echo "Usage: $0 {start|stop|restart}"
exit 1
;;
esac

Functions

Basic Function

greet() {
echo "Hello, $1!"
}

greet "Alice" # Hello, Alice!

Function with Local Variables

calculate() {
local x=$1
local y=$2
local result=$((x + y))
echo $result
}

sum=$(calculate 10 20)
echo "Sum: $sum" # Sum: 30

Function Return Values

is_positive() {
if [ $1 -gt 0 ]; then
return 0 # Success
else
return 1 # Failure
fi
}

if is_positive 5; then
echo "5 is positive"
fi

Capture output:

get_user_info() {
echo "Alice:30:NYC"
}

info=$(get_user_info)
echo "$info" # Alice:30:NYC

Exit Codes & Error Handling

Exit Codes

Every command returns an exit code (0 = success, non-zero = failure):

ls /nonexistent 2>/dev/null
echo $? # Non-zero (command failed)

Check exit code immediately:

if command; then
echo "Success"
else
echo "Failed"
fi

Error Prevention

Set error flags:

#!/bin/bash
set -e # Exit on any error
set -u # Exit if undefined variable used
set -o pipefail # Return error if pipe command fails

Handle errors:

command || {
echo "Error occurred"
exit 1
}

Built-in Commands

CommandPurpose
echoPrint text
printfFormatted output
readRead user input
test / [Evaluate condition
pwdPrint working directory
cdChange directory
exportSet environment variable
source / .Execute commands from file
typeShow command type
commandExecute command

Exercises

Exercise 1: Temperature Converter

Create a script that converts Celsius to Fahrenheit:

#!/bin/bash

if [ $# -ne 1 ]; then
echo "Usage: $0 <celsius>"
exit 1
fi

celsius=$1
fahrenheit=$(echo "scale=2; $celsius * 9/5 + 32" | bc)
echo "$celsius°C = $fahrenheit°F"

Exercise 2: File Info Script

Create a script that displays file information:

#!/bin/bash

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

echo "File: $1"
echo "Size: $(wc -c < "$1") bytes"
echo "Lines: $(wc -l < "$1")"
echo "Modified: $(stat -c %y "$1")"

Exercise 3: Array Processing

Create a script that processes an array:

#!/bin/bash

numbers=(5 12 3 8 15 2)
sum=0
count=0

for num in "${numbers[@]}"; do
sum=$((sum + num))
((count++))
done

average=$((sum / count))
echo "Sum: $sum"
echo "Count: $count"
echo "Average: $average"

Exercise 4: Simple Menu

Create an interactive menu system:

#!/bin/bash

while true; do
echo "=== Menu ==="
echo "1) List files"
echo "2) Show current directory"
echo "3) Exit"
read -p "Choose option: " choice

case $choice in
1) ls -l ;;
2) pwd ;;
3) exit 0 ;;
*) echo "Invalid choice" ;;
esac
done

Key Takeaways

  • Variables are dynamically typed; use $ or ${} to expand
  • Quotes control expansion: "" (expand) vs '' (literal)
  • Arrays are 0-indexed; associative arrays use keys
  • Control structures (if/for/while/case) power script logic
  • Functions promote reusability and code organization
  • Exit codes (0 = success) drive error handling
  • Use set -e and set -u to catch common errors early

Next Steps

Explore Advanced Bash topics like process substitution, here documents, signal handling, and text processing with sed/awk.