Skip to content

Bash - Bourne Again Shell

Bash (Bourne Again Shell) is a Unix shell and command language written by Brian Fox for the GNU Project as a free software replacement for the Bourne Shell. First released in 1989, Bash has become the default shell on most Linux distributions and is one of the most widely used shells in the Unix/Linux ecosystem. It combines the features of the original Bourne shell with additional functionality including command completion, command history, and improved scripting capabilities.

Installation and Setup

Checking Bash Installation

bash
# Check if Bash is installed
which bash
/bin/bash

# Check Bash version
bash --version
GNU bash, version 5.1.16(1)-release (x86_64-pc-linux-gnu)

# Check current shell
echo $SHELL
/bin/bash

# Check available shells
cat /etc/shells

Setting Bash as Default Shell

bash
# Set Bash as default shell for current user
chsh -s /bin/bash

# Set Bash as default shell for specific user (as root)
sudo chsh -s /bin/bash username

# Verify shell change
echo $SHELL

Bash Installation on Different Systems

bash
# Ubuntu/Debian
sudo apt update && sudo apt install bash

# CentOS/RHEL/Fedora
sudo dnf install bash

# macOS (using Homebrew for latest version)
brew install bash

# Arch Linux
sudo pacman -S bash

# FreeBSD
pkg install bash

Basic Bash Syntax and Commands

Command Structure

bash
# Basic command structure
command [options] [arguments]

# Examples
ls -la /home
cp file1.txt file2.txt
grep -r "pattern" /path/to/search

Variables and Environment

bash
# Variable assignment (no spaces around =)
name="John Doe"
age=30
path="/home/user"

# Using variables
echo $name
echo ${name}
echo "Hello, $name"

# Environment variables
export PATH="/usr/local/bin:$PATH"
export EDITOR="vim"

# Special variables
echo $0    # Script name
echo $1    # First argument
echo $#    # Number of arguments
echo $@    # All arguments
echo $$    # Process ID
echo $?    # Exit status of last command

Command Substitution

bash
# Using $() (preferred)
current_date=$(date)
file_count=$(ls | wc -l)
user_home=$(eval echo ~$USER)

# Using backticks (legacy)
current_date=`date`
file_count=`ls | wc -l`

# Nested command substitution
echo "Today is $(date +%A), $(date +%B) $(date +%d)"

Quoting and Escaping

bash
# Single quotes (literal)
echo 'The variable $HOME is not expanded'

# Double quotes (variable expansion)
echo "Your home directory is $HOME"

# Escaping special characters
echo "The price is \$10"
echo "Use \"quotes\" inside quotes"

# Here documents
cat << EOF
This is a multi-line
text block that can contain
variables like $HOME
EOF

# Here strings
grep "pattern" <<< "$variable"

File Operations and Navigation

Directory Navigation

bash
# Change directory
cd /path/to/directory
cd ~                    # Home directory
cd -                    # Previous directory
cd ..                   # Parent directory
cd ../..                # Two levels up

# Print working directory
pwd

# Directory stack operations
pushd /path/to/dir      # Push directory onto stack
popd                    # Pop directory from stack
dirs                    # Show directory stack

File and Directory Listing

bash
# Basic listing
ls
ls -l                   # Long format
ls -la                  # Long format with hidden files
ls -lh                  # Human readable sizes
ls -lt                  # Sort by modification time
ls -lS                  # Sort by size
ls -lR                  # Recursive listing

# Advanced listing options
ls -la --color=auto     # Colored output
ls -la --time-style=full-iso  # ISO time format
ls -la --group-directories-first  # Directories first

File Operations

bash
# Create files
touch file.txt
touch file1.txt file2.txt file3.txt

# Copy files and directories
cp source.txt destination.txt
cp -r source_dir/ destination_dir/
cp -p file.txt backup.txt    # Preserve attributes
cp -u source.txt dest.txt    # Update only if newer

# Move and rename
mv old_name.txt new_name.txt
mv file.txt /path/to/destination/
mv *.txt /path/to/directory/

# Remove files and directories
rm file.txt
rm -f file.txt              # Force removal
rm -r directory/            # Recursive removal
rm -rf directory/           # Force recursive removal
rm -i *.txt                 # Interactive removal

# Create directories
mkdir directory_name
mkdir -p path/to/nested/directory
mkdir -m 755 directory_name  # With specific permissions

File Permissions and Ownership

bash
# Change permissions
chmod 755 file.txt
chmod u+x script.sh         # Add execute for user
chmod g-w file.txt          # Remove write for group
chmod o=r file.txt          # Set read-only for others
chmod -R 644 directory/     # Recursive permission change

# Change ownership
chown user:group file.txt
chown -R user:group directory/
chgrp group file.txt        # Change group only

# View permissions
ls -l file.txt
stat file.txt               # Detailed file information

Text Processing and Manipulation

File Content Operations

bash
# View file contents
cat file.txt                # Display entire file
less file.txt               # Paginated view
more file.txt               # Simple paginated view
head file.txt               # First 10 lines
head -n 20 file.txt         # First 20 lines
tail file.txt               # Last 10 lines
tail -n 20 file.txt         # Last 20 lines
tail -f file.txt            # Follow file changes

# File comparison
diff file1.txt file2.txt
diff -u file1.txt file2.txt  # Unified format
cmp file1.txt file2.txt      # Binary comparison

Text Search and Filtering

bash
# grep - pattern searching
grep "pattern" file.txt
grep -i "pattern" file.txt   # Case insensitive
grep -r "pattern" directory/ # Recursive search
grep -n "pattern" file.txt   # Show line numbers
grep -v "pattern" file.txt   # Invert match
grep -E "pattern1|pattern2" file.txt  # Extended regex

# Advanced grep options
grep -A 3 "pattern" file.txt # Show 3 lines after match
grep -B 3 "pattern" file.txt # Show 3 lines before match
grep -C 3 "pattern" file.txt # Show 3 lines around match
grep -l "pattern" *.txt      # Show only filenames
grep -c "pattern" file.txt   # Count matches

Text Processing Tools

bash
# sed - stream editor
sed 's/old/new/' file.txt           # Replace first occurrence
sed 's/old/new/g' file.txt          # Replace all occurrences
sed '1,5s/old/new/g' file.txt       # Replace in lines 1-5
sed '/pattern/d' file.txt           # Delete lines matching pattern
sed -n '1,10p' file.txt             # Print lines 1-10

# awk - pattern scanning and processing
awk '{print $1}' file.txt           # Print first column
awk '{print $NF}' file.txt          # Print last column
awk '/pattern/ {print $0}' file.txt # Print lines matching pattern
awk -F: '{print $1}' /etc/passwd    # Use : as field separator
awk '{sum += $1} END {print sum}' file.txt  # Sum first column

# cut - extract columns
cut -d: -f1 /etc/passwd             # Extract first field
cut -c1-10 file.txt                 # Extract characters 1-10
cut -f2,4 file.txt                  # Extract fields 2 and 4

# sort and uniq
sort file.txt                       # Sort lines
sort -n file.txt                    # Numeric sort
sort -r file.txt                    # Reverse sort
sort -k2 file.txt                   # Sort by second field
uniq file.txt                       # Remove duplicate lines
sort file.txt | uniq -c             # Count occurrences

Input/Output Redirection and Pipes

Redirection Operators

bash
# Output redirection
command > file.txt              # Redirect stdout to file (overwrite)
command >> file.txt             # Redirect stdout to file (append)
command 2> error.log            # Redirect stderr to file
command 2>> error.log           # Redirect stderr to file (append)
command &> output.log           # Redirect both stdout and stderr
command > output.log 2>&1       # Redirect both stdout and stderr

# Input redirection
command < input.txt             # Read input from file
command << EOF                  # Here document
line 1
line 2
EOF

# Advanced redirection
command 3> file.txt             # Redirect to file descriptor 3
exec 3> file.txt                # Open file descriptor 3
echo "text" >&3                 # Write to file descriptor 3
exec 3>&-                       # Close file descriptor 3

Pipes and Command Chaining

bash
# Basic pipes
ls -l | grep "txt"              # List files and filter for .txt
ps aux | grep "process_name"    # Show processes and filter
cat file.txt | sort | uniq      # Sort and remove duplicates

# Complex pipe chains
cat /var/log/access.log | grep "404" | awk '{print $1}' | sort | uniq -c | sort -nr
find . -name "*.log" | xargs grep "ERROR" | cut -d: -f1 | sort | uniq

# Tee command (split output)
command | tee file.txt          # Write to file and stdout
command | tee -a file.txt       # Append to file and stdout

Process Management

Job Control

bash
# Background and foreground jobs
command &                       # Run command in background
jobs                           # List active jobs
fg %1                          # Bring job 1 to foreground
bg %1                          # Send job 1 to background
kill %1                        # Kill job 1

# Process control signals
Ctrl+C                         # Interrupt (SIGINT)
Ctrl+Z                         # Suspend (SIGTSTP)
Ctrl+\                         # Quit (SIGQUIT)

Process Information

bash
# Process listing
ps                             # Show current processes
ps aux                         # Show all processes
ps -ef                         # Full format listing
pstree                         # Show process tree
top                            # Real-time process monitor
htop                           # Enhanced process monitor

# Process management
kill PID                       # Terminate process
kill -9 PID                    # Force kill process
killall process_name           # Kill all processes by name
pkill pattern                  # Kill processes matching pattern
nohup command &                # Run command immune to hangups

Bash Scripting Fundamentals

Script Structure

bash
#!/bin/bash
# Script description and metadata
# Author: Your Name
# Date: YYYY-MM-DD
# Version: 1.0

# Script content starts here
echo "Hello, World!"

Variables and Data Types

bash
# String variables
name="John Doe"
message='Hello, World!'
multiline="This is a
multi-line string"

# Numeric variables
number=42
pi=3.14159

# Arrays
fruits=("apple" "banana" "orange")
numbers=(1 2 3 4 5)

# Associative arrays (Bash 4+)
declare -A colors
colors[red]="#FF0000"
colors[green]="#00FF00"
colors[blue]="#0000FF"

# Array operations
echo ${fruits[0]}               # First element
echo ${fruits[@]}               # All elements
echo ${#fruits[@]}              # Array length
fruits+=("grape")               # Append element

Conditional Statements

bash
# if-then-else
if [ condition ]; then
    echo "Condition is true"
elif [ other_condition ]; then
    echo "Other condition is true"
else
    echo "No condition is true"
fi

# Test conditions
if [ "$var" = "value" ]; then          # String equality
if [ "$num" -eq 10 ]; then             # Numeric equality
if [ "$num" -gt 5 ]; then              # Greater than
if [ "$num" -lt 20 ]; then             # Less than
if [ -f "file.txt" ]; then             # File exists
if [ -d "directory" ]; then            # Directory exists
if [ -r "file.txt" ]; then             # File is readable
if [ -w "file.txt" ]; then             # File is writable
if [ -x "script.sh" ]; then            # File is executable

# Logical operators
if [ condition1 ] && [ condition2 ]; then    # AND
if [ condition1 ] || [ condition2 ]; then    # OR
if [ ! condition ]; then                     # NOT

# Case statement
case $variable in
    pattern1)
        echo "Matched pattern1"
        ;;
    pattern2|pattern3)
        echo "Matched pattern2 or pattern3"
        ;;
    *)
        echo "No pattern matched"
        ;;
esac

Loops

bash
# for loop
for i in {1..10}; do
    echo "Number: $i"
done

for file in *.txt; do
    echo "Processing: $file"
done

for item in "${array[@]}"; do
    echo "Item: $item"
done

# C-style for loop
for ((i=1; i<=10; i++)); do
    echo "Counter: $i"
done

# while loop
counter=1
while [ $counter -le 10 ]; do
    echo "Counter: $counter"
    ((counter++))
done

# until loop
counter=1
until [ $counter -gt 10 ]; do
    echo "Counter: $counter"
    ((counter++))
done

# Loop control
for i in {1..10}; do
    if [ $i -eq 5 ]; then
        continue    # Skip iteration
    fi
    if [ $i -eq 8 ]; then
        break      # Exit loop
    fi
    echo $i
done

Functions

bash
# Function definition
function greet() {
    echo "Hello, $1!"
}

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

# Function with return value
calculate_sum() {
    local num1=$1
    local num2=$2
    local sum=$((num1 + num2))
    echo $sum
}

# Function with local variables
process_file() {
    local filename=$1
    local line_count=$(wc -l < "$filename")
    echo "File $filename has $line_count lines"
}

# Function usage
greet "World"
result=$(calculate_sum 5 3)
echo "Sum: $result"

Advanced Bash Features

Parameter Expansion

bash
# Basic parameter expansion
echo ${variable}
echo ${variable:-default}       # Use default if unset
echo ${variable:=default}       # Set default if unset
echo ${variable:+alternate}     # Use alternate if set
echo ${variable:?error}         # Error if unset

# String manipulation
string="Hello, World!"
echo ${string#Hello}            # Remove shortest match from beginning
echo ${string##*/}              # Remove longest match from beginning
echo ${string%World!}           # Remove shortest match from end
echo ${string%%/*}              # Remove longest match from end
echo ${string/Hello/Hi}         # Replace first occurrence
echo ${string//l/L}             # Replace all occurrences

# Substring extraction
echo ${string:0:5}              # Extract substring (position:length)
echo ${string:7}                # Extract from position to end
echo ${#string}                 # String length

Arithmetic Operations

bash
# Arithmetic expansion
result=$((5 + 3))
result=$((10 * 2))
result=$((20 / 4))
result=$((17 % 5))              # Modulo

# Increment/decrement
((counter++))
((counter--))
((counter += 5))
((counter -= 3))

# Arithmetic with variables
num1=10
num2=5
sum=$((num1 + num2))
product=$((num1 * num2))

# Floating point arithmetic (using bc)
result=$(echo "scale=2; 10/3" | bc)
result=$(echo "scale=4; sqrt(16)" | bc -l)

Error Handling

bash
# Exit on error
set -e                          # Exit on any error
set -u                          # Exit on undefined variable
set -o pipefail                 # Exit on pipe failure

# Error handling in scripts
command || {
    echo "Command failed"
    exit 1
}

# Trap signals
trap 'echo "Script interrupted"; exit 1' INT TERM
trap 'cleanup_function' EXIT

# Function error handling
safe_command() {
    if ! command_that_might_fail; then
        echo "Error: Command failed" >&2
        return 1
    fi
}

Configuration and Customization

Bash Configuration Files

bash
# System-wide configuration
/etc/bash.bashrc                # System-wide bashrc
/etc/profile                    # System-wide profile

# User-specific configuration
~/.bashrc                       # User's bashrc
~/.bash_profile                 # User's profile
~/.bash_login                   # Login shell configuration
~/.profile                      # POSIX shell profile
~/.bash_logout                  # Logout script

Customizing .bashrc

bash
# ~/.bashrc example configuration

# Source global definitions
if [ -f /etc/bashrc ]; then
    . /etc/bashrc
fi

# User specific environment
export EDITOR="vim"
export BROWSER="firefox"
export PAGER="less"

# Custom PATH
export PATH="$HOME/bin:$HOME/.local/bin:$PATH"

# Aliases
alias ll='ls -alF'
alias la='ls -A'
alias l='ls -CF'
alias grep='grep --color=auto'
alias fgrep='fgrep --color=auto'
alias egrep='egrep --color=auto'

# Custom functions
mkcd() {
    mkdir -p "$1" && cd "$1"
}

extract() {
    if [ -f $1 ] ; then
        case $1 in
            *.tar.bz2)   tar xjf $1     ;;
            *.tar.gz)    tar xzf $1     ;;
            *.bz2)       bunzip2 $1     ;;
            *.rar)       unrar e $1     ;;
            *.gz)        gunzip $1      ;;
            *.tar)       tar xf $1      ;;
            *.tbz2)      tar xjf $1     ;;
            *.tgz)       tar xzf $1     ;;
            *.zip)       unzip $1       ;;
            *.Z)         uncompress $1  ;;
            *.7z)        7z x $1        ;;
            *)     echo "'$1' cannot be extracted via extract()" ;;
        esac
    else
        echo "'$1' is not a valid file"
    fi
}

# Prompt customization
PS1='\[\033[01;32m\]\u@\h\[\033[00m\]:\[\033[01;34m\]\w\[\033[00m\]\$ '

# History configuration
HISTSIZE=10000
HISTFILESIZE=20000
HISTCONTROL=ignoredups:ignorespace
shopt -s histappend

# Shell options
shopt -s checkwinsize
shopt -s globstar
shopt -s cdspell

Bash Options and Settings

bash
# Set options
set -o vi                       # Vi editing mode
set -o emacs                    # Emacs editing mode (default)
set -o noclobber                # Prevent file overwriting
set +o noclobber                # Allow file overwriting

# Shopt options
shopt -s autocd                 # Auto cd to directory
shopt -s cdspell                # Correct minor spelling errors
shopt -s checkwinsize           # Update LINES and COLUMNS
shopt -s cmdhist                # Save multi-line commands
shopt -s dotglob                # Include hidden files in globbing
shopt -s expand_aliases         # Expand aliases
shopt -s extglob                # Extended globbing
shopt -s globstar               # ** recursive globbing
shopt -s histappend             # Append to history file
shopt -s nocaseglob             # Case-insensitive globbing

Command Line Editing and History

Command Line Editing

bash
# Emacs mode (default)
Ctrl+A                          # Beginning of line
Ctrl+E                          # End of line
Ctrl+B                          # Back one character
Ctrl+F                          # Forward one character
Alt+B                           # Back one word
Alt+F                           # Forward one word
Ctrl+D                          # Delete character
Ctrl+H                          # Backspace
Ctrl+K                          # Kill to end of line
Ctrl+U                          # Kill to beginning of line
Ctrl+W                          # Kill previous word
Alt+D                           # Kill next word
Ctrl+Y                          # Yank (paste)
Ctrl+T                          # Transpose characters
Alt+T                           # Transpose words

# Vi mode
set -o vi
Esc                             # Enter command mode
i                               # Insert mode
a                               # Append mode
A                               # Append at end of line
I                               # Insert at beginning of line

History Management

bash
# History commands
history                         # Show command history
history 10                      # Show last 10 commands
history -c                      # Clear history
history -d 5                    # Delete history entry 5

# History expansion
!!                              # Previous command
!n                              # Command number n
!string                         # Last command starting with string
!?string                        # Last command containing string
^old^new                        # Replace old with new in previous command

# History search
Ctrl+R                          # Reverse search
Ctrl+S                          # Forward search
Ctrl+G                          # Cancel search

# History configuration
export HISTSIZE=10000           # Commands in memory
export HISTFILESIZE=20000       # Commands in file
export HISTCONTROL=ignoredups   # Ignore duplicates
export HISTIGNORE="ls:ll:cd:pwd:bg:fg:history"  # Ignore commands
export HISTTIMEFORMAT="%F %T "  # Add timestamps

Debugging and Troubleshooting

Debugging Scripts

bash
# Debug modes
bash -x script.sh               # Execute with trace
bash -n script.sh               # Check syntax without execution
bash -v script.sh               # Verbose mode

# Debug options in script
set -x                          # Enable trace
set +x                          # Disable trace
set -v                          # Enable verbose
set +v                          # Disable verbose

# Conditional debugging
if [ "$DEBUG" = "1" ]; then
    set -x
fi

# Debug function
debug() {
    if [ "$DEBUG" = "1" ]; then
        echo "DEBUG: $*" >&2
    fi
}

Error Checking

bash
# Check command success
if command; then
    echo "Command succeeded"
else
    echo "Command failed"
fi

# Check exit status
command
if [ $? -eq 0 ]; then
    echo "Success"
else
    echo "Failed with exit code $?"
fi

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

# Check file existence
if [ ! -f "$filename" ]; then
    echo "Error: File $filename does not exist"
    exit 1
fi

Performance Monitoring

bash
# Time command execution
time command
time { command1; command2; }

# Profile script execution
PS4='+ $(date "+%s.%N"): '
set -x
# Your commands here
set +x

# Memory usage
/usr/bin/time -v command

# Disk usage
du -sh directory/
df -h

Best Practices and Security

Script Security

bash
# Use full paths for commands
/bin/ls instead of ls
/usr/bin/find instead of find

# Validate input
case "$input" in
    [a-zA-Z0-9]*)
        # Valid input
        ;;
    *)
        echo "Invalid input"
        exit 1
        ;;
esac

# Quote variables
rm "$filename"                  # Correct
rm $filename                    # Dangerous

# Use arrays for file lists
files=( *.txt )
for file in "${files[@]}"; do
    process "$file"
done

Performance Best Practices

bash
# Use built-in commands when possible
[[ condition ]]                 # Instead of [ condition ]
(( arithmetic ))                # Instead of [ arithmetic ]

# Avoid unnecessary subshells
var=$(cat file)                 # Subshell
var=$(<file)                    # Built-in

# Use parameter expansion
${var#pattern}                  # Instead of sed/awk for simple operations
${var%pattern}
${var/pattern/replacement}

# Efficient loops
while IFS= read -r line; do     # Read file line by line
    process "$line"
done < file.txt

Code Organization

bash
# Use functions for repeated code
log_message() {
    echo "[$(date '+%Y-%m-%d %H:%M:%S')] $*" >&2
}

# Separate configuration
CONFIG_FILE="${HOME}/.myapp.conf"
if [ -f "$CONFIG_FILE" ]; then
    source "$CONFIG_FILE"
fi

# Use meaningful variable names
user_count=10                   # Good
uc=10                          # Poor

# Comment complex logic
# Calculate the number of days between two dates
start_date=$(date -d "$1" +%s)
end_date=$(date -d "$2" +%s)
days=$(( (end_date - start_date) / 86400 ))

Bash remains the most widely used shell in Unix and Linux environments, providing a powerful combination of interactive command-line interface and scripting language. Its extensive feature set, POSIX compliance, and widespread availability make it an essential tool for system administrators, developers, and power users. Whether used for simple command execution or complex automation scripts, Bash offers the flexibility and reliability needed for professional computing environments.