Skip to main content

Bash Complete Guide - Learn Shell Scripting from Scratch

• 6 min read
bash shell scripting linux unix automation command line bash tutorial

Quick Answer: What Is Bash and Why Learn It?

Bash is a shell and programming language that’s the default on Linux and macOS. Learn it to automate tasks, manage systems, and write powerful scripts. Start with variables (name="value"), loops (for file in *.txt; do...done), and conditionals (if [ condition ]; then...fi).

Quick Comparison: Why Bash Over Alternatives?

FeatureBashPythonshzsh
Installed by defaultLinux/macOSNoMost UnixSome systems
Script portabilityExcellentPoorExcellentGood
Learning curveModerateEasyVery easySteep
Best forSystem admin, DevOpsGeneral purposePOSIX scriptsInteractive shell
Script lengthMedium (50-500 lines)Any lengthShortMedium

Bottom line: Learn Bash for system automation and scripts under 500 lines. Use Python for larger, more complex programs.


Bash is the most widely used shell on Unix-like systems, combining a command-line interface with a powerful scripting language. This comprehensive guide teaches you everything from basic commands to advanced automation, with practical examples you can use immediately.

Whether you’re a system administrator automating routine tasks, a DevOps engineer managing infrastructure, or a developer looking to enhance your skills, this guide provides the knowledge and hands-on examples to master Bash.

Table of Contents

  1. What is Bash?
  2. Installing and Setting Up Bash
  3. Bash Basics
  4. Variables and Data Types
  5. Operators
  6. Control Flow
  7. Functions
  8. Working with Files
  9. String Manipulation
  10. Text Processing
  11. Error Handling
  12. Best Practices
  13. Frequently Asked Questions

What is Bash?

Bash (Bourne Again Shell) is a Unix shell and command language—it’s both an interactive command line where you type commands directly, and a programming language for writing scripts. It’s the default shell on most Linux distributions and macOS, which makes it essential knowledge for anyone working with servers, development, or system administration.

You might be wondering: “Isn’t it just a command line?” Yes and no. As a command line, it lets you run commands directly. As a programming language, it lets you combine those commands into scripts that automate complex tasks. This duality is why Bash is so powerful—the same commands you type interactively can be put in a script and run repeatedly or in different contexts.

Key Characteristics

Bash has features that make it perfect for system automation:

  • Command-line interface: Interactive shell for executing commands directly—you type, it runs
  • Scripting language: Full programming language for automation—you can write scripts that contain logic, loops, and conditionals
  • Portable: Runs on Linux, macOS, Windows (via WSL), and Unix systems—write once, run anywhere (mostly)
  • Backward compatible: Works with original Bourne shell scripts—older scripts still work
  • Extensible: Supports functions, aliases, and built-in commands—you can add your own custom commands

Bash vs. Other Shells

If you’re wondering whether to learn Bash or something else, consider what you’re trying to do:

FeatureBashsh (original)zshfish
ScriptingFull languageLimitedFull languageFull language
PortableVery highVery highHighMedium
Learning curveMediumEasySteepEasy
Cross-platformExcellentExcellentGoodGood

Bash is the safe choice for production scripts because it’s available everywhere. sh is the most portable but more limited. zsh and fish are more feature-rich for interactive use but less portable. For learning and production work, Bash is the standard.


Installing and Setting Up Bash

Check Your Bash Version

bash --version
# Output: GNU bash, version 5.1.16(1)-release (x86_64-apple-darwin20.6.0)

Verify Current Shell

echo $SHELL
# Output: /bin/bash

Install Bash

macOS (using Homebrew):

brew install bash

Ubuntu/Debian:

sudo apt-get update
sudo apt-get install bash

CentOS/RHEL:

sudo yum install bash

Bash Basics

Your First Command

The simplest Bash command:

echo "Hello, Bash!"
# Output: Hello, Bash!

Command Structure

Every Bash command follows this pattern:

command [options] [arguments]

Example:

ls -la /home/user
# ls = command
# -la = options
# /home/user = argument

Creating Your First Script

Create a file named hello.sh:

#!/bin/bash

echo "Welcome to Bash scripting!"
echo "The date is: $(date)"

Make it executable:

chmod +x hello.sh

Run it:

./hello.sh
# Output:
# Welcome to Bash scripting!
# The date is: Fri Feb 21 10:30:45 UTC 2026

Variables and Data Types

Variable Assignment

Bash variables are simple to create:

# Variable assignment (no spaces around =)
name="John"
age=30
price=19.99

# Access variables with $
echo "Hello, $name"
echo "Age: $age"

Variable Naming Rules

  • Must start with letter or underscore
  • Can contain letters, numbers, underscores
  • Case-sensitive (Name, name, NAME are different)
  • Avoid spaces around the equals sign

Special Variables

$0      # Script name
$1-$9   # Positional arguments
$#      # Number of arguments
$*      # All arguments as one string
$@      # All arguments as separate strings
$?      # Exit code of last command
$$      # Process ID
$!      # Process ID of last background job

Example with Arguments

Create greet.sh:

#!/bin/bash

echo "Script: $0"
echo "First arg: $1"
echo "Second arg: $2"
echo "All args: $@"
echo "Number of args: $#"

Run it:

./greet.sh Alice Bob Charlie
# Output:
# Script: ./greet.sh
# First arg: Alice
# Second arg: Bob
# All args: Alice Bob Charlie
# Number of args: 3

String Variables

# String concatenation
first="John"
last="Doe"
full="$first $last"
echo $full  # Output: John Doe

# String length
text="Bash"
echo ${#text}  # Output: 4

Operators

Arithmetic Operators

# Arithmetic expansion
result=$((10 + 5))
echo $result  # Output: 15

# Common arithmetic operators
echo $((10 - 3))   # Subtraction: 7
echo $((4 * 5))    # Multiplication: 20
echo $((20 / 4))   # Division: 5
echo $((17 % 5))   # Modulo: 2
echo $((2 ** 3))   # Exponent: 8

Comparison Operators (Numbers)

a=10
b=20

if [ $a -eq $b ]; then echo "Equal"; fi           # Equal
if [ $a -ne $b ]; then echo "Not equal"; fi       # Not equal
if [ $a -lt $b ]; then echo "Less than"; fi       # Less than
if [ $a -gt $b ]; then echo "Greater than"; fi    # Greater than
if [ $a -le $b ]; then echo "Less or equal"; fi   # Less or equal
if [ $a -ge $b ]; then echo "Greater or equal"; fi # Greater or equal

String Comparison

text1="bash"
text2="bash"

if [ "$text1" = "$text2" ]; then
  echo "Strings are equal"
fi

if [ "$text1" != "$text2" ]; then
  echo "Strings are different"
fi

# Check if string is empty
if [ -z "$text1" ]; then
  echo "String is empty"
fi

Control Flow

If-Else Statements

age=25

if [ $age -lt 18 ]; then
  echo "You are a minor"
elif [ $age -lt 65 ]; then
  echo "You are an adult"
else
  echo "You are a senior"
fi
# Output: You are an adult

For Loops

Looping through numbers:

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

Looping through items:

for fruit in apple banana orange; do
  echo "I like $fruit"
done

C-style for loop:

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

While Loops

counter=1

while [ $counter -le 5 ]; do
  echo "Count: $counter"
  counter=$((counter + 1))
done

Case Statements

day="Monday"

case $day in
  Monday)
    echo "Start of work week"
    ;;
  Friday)
    echo "Almost weekend!"
    ;;
  Saturday|Sunday)
    echo "Weekend!"
    ;;
  *)
    echo "Regular day"
    ;;
esac
# Output: Start of work week

Functions

Basic Function Syntax

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

# Call function
greet "Alice"
# Output: Hello, Alice!

Function Parameters

add() {
  local sum=$((${1} + ${2}))
  echo $sum
}

result=$(add 5 3)
echo "Sum: $result"
# Output: Sum: 8

Function Return Values

is_even() {
  if [ $((${1} % 2)) -eq 0 ]; then
    return 0  # Success
  else
    return 1  # Failure
  fi
}

is_even 4
if [ $? -eq 0 ]; then
  echo "4 is even"
fi

Working with Files

Check File Status

file="/path/to/file.txt"

# File exists
if [ -f "$file" ]; then
  echo "File exists"
fi

# Directory exists
if [ -d "/path/to/dir" ]; then
  echo "Directory exists"
fi

# File is readable
if [ -r "$file" ]; then
  echo "File is readable"
fi

# File is writable
if [ -w "$file" ]; then
  echo "File is writable"
fi

Reading File Content

# Read entire file
cat filename.txt

# Read line by line
while IFS= read -r line; do
  echo "Line: $line"
done < filename.txt

Writing to Files

# Write to file (overwrite)
echo "Hello, World!" > output.txt

# Append to file
echo "Additional line" >> output.txt

# Write multiple lines
cat > myfile.txt << EOF
This is line 1
This is line 2
This is line 3
EOF

String Manipulation

Substring Extraction

text="Bash Programming"

# Extract first 4 characters
echo ${text:0:4}  # Output: Bash

# Extract from position 5 to end
echo ${text:5}    # Output: Programming

# Last 3 characters
echo ${text: -3}  # Output: ing

String Replacement

text="Hello World"

# Replace first occurrence
echo ${text/World/Universe}
# Output: Hello Universe

# Replace all occurrences
text="cat cat cat"
echo ${text//cat/dog}
# Output: dog dog dog

Convert Case

text="Hello"

# Uppercase (Bash 4+)
echo ${text^^}  # Output: HELLO

# Lowercase (Bash 4+)
echo ${text,,}  # Output: hello

Text Processing

Using grep

# Find lines containing text
grep "error" logfile.txt

# Count matching lines
grep -c "error" logfile.txt

# Ignore case
grep -i "ERROR" logfile.txt

Using sed

# Replace text
sed 's/old/new/' file.txt

# Replace all occurrences
sed 's/old/new/g' file.txt

# Edit file in place
sed -i 's/old/new/g' file.txt

Using awk

# Print specific column
awk '{print $1}' file.txt

# Filter by condition
awk '$3 > 100 {print $1, $3}' file.txt

# Calculate sum
awk '{sum += $1} END {print sum}' file.txt

Error Handling

Check Exit Codes

ls /nonexistent 2>/dev/null
if [ $? -ne 0 ]; then
  echo "Directory not found"
fi

Using set Options

#!/bin/bash

# Exit on error
set -e

# Exit on undefined variable
set -u

# Print commands before executing
set -x

# Safe by default
set -euo pipefail

Try-Catch Pattern

execute_command() {
  if ! "$@"; then
    echo "Command failed: $*" >&2
    return 1
  fi
}

execute_command ls /nonexistent

Best Practices

1. Always Quote Variables

# Good
name="$1"
echo "Hello, $name"

# Risky (breaks if name contains spaces)
echo Hello, $1

2. Use Functions for Reusability

# Good
log() {
  echo "[$(date +'%Y-%m-%d %H:%M:%S')] $*"
}

log "Script started"

3. Add Comments

#!/bin/bash
# Purpose: Backup user files
# Author: Admin
# Date: 2026-02-21

# Create backup directory
mkdir -p ~/backups

4. Validate Input

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

5. Use Meaningful Names

# Good
user_count=10
backup_dir="/home/backups"

# Avoid
uc=10
bd="/home/backups"

Frequently Asked Questions

Q: What’s the difference between sh and bash?

A: sh is the original Bourne shell with minimal features. Bash extends sh with additional features like arrays, functions, and arithmetic. While Bash is backward compatible with sh, some Bash-specific features won’t work in pure sh.

Q: Should I use [ ] or [[ ]] for conditions?

A: Use [[ ]] in Bash when possible. It’s more robust, supports regex matching, and handles spaces better. Use [ ] only for POSIX compatibility.

Q: How do I debug a Bash script?

A: Use set -x to trace execution, or run bash -x script.sh. You can also add echo statements to debug specific variables.

Q: What’s the difference between $@ and $*?

A: $@ passes each argument as a separate string (safer), while $* concatenates all arguments. Always use $@ unless you specifically need concatenation.

Q: How do I create a reusable script library?

A: Create a library file with functions, then source it in your scripts using source library.sh or . library.sh.


Next Steps

Now that you understand Bash fundamentals, explore these related topics:

Summary

Bash is a powerful tool for automation and system administration. With the fundamentals covered in this guide—variables, operators, control flow, functions, and file operations—you’re ready to start writing practical scripts. The key is practice: write scripts, test them, and gradually build your expertise.

Start with simple scripts, gradually increase complexity, and refer back to this guide as needed. Happy scripting!