A digital illustration of a computer terminal showing Bash commands and scripts on a dark background

Mastering Bash โ€” The Complete Hands-On Guide

, ,

Foreword

This comprehensive guide to Bash is designed for readers of all levels โ€” from beginners who are opening the terminal for the first time to experienced users looking to refine their scripting skills.

The tutorial takes a conversational, hands-on approach. Weโ€™ll not only learn the syntax of Bash commands but understand why they work, how the shell interprets them, and how to use them safely and effectively in real-world automation.

Every section includes conceptual explanations, practical examples, outputs, and best practices. By the end, youโ€™ll have a solid foundation for writing robust Bash scripts and automating everyday tasks with confidence.

Letโ€™s begin mastering Bash โ€” one command at a time.

1. Introduction to Bash

Bash (Bourne Again Shell) is the most common command interpreter on Unix-like systems. It allows you to interact with your system, run programs, automate repetitive tasks, and glue together complex workflows.

When you type a command and press Enter, Bash parses your input, expands variables, performs globbing (pattern matching), and launches the requested program as a child process. Understanding this execution model is the foundation for every script youโ€™ll write.

There are three main ways Bash runs:

  • Interactive shell โ€” You enter commands one at a time and see the results immediately.
  • Non-interactive shell โ€” Used to run scripts and automate tasks without user input.
  • Login shell โ€” Executed when you log in to a system; it loads your environment variables and startup scripts like ~/.bash_profile or /etc/profile.

First Commands

echo "Hello, Bash!"
pwd
whoami
date
Output:
Hello, Bash!
/home/user
user
Mon Jan 22 10:34:15 UTC 2026

These simple commands demonstrate standard output and basic interaction with the system. In scripts, each command returns an exit status code stored in $? (0 for success, non-zero for error).

What to Remember

  • Bash is a shell and a language for automation.
  • Interactive vs non-interactive shells behave slightly differently.
  • Each command returns an exit status you can test later.

2. Running Bash Scripts

Bash scripts are plain text files containing one or more shell commands. To execute a script, Bash must know which interpreter to use. This is specified by the first line โ€” the shebang:

#!/usr/bin/env bash
echo "This is my first script!"

Save the file as hello.sh and make it executable:

chmod +x hello.sh
./hello.sh
Output:
This is my first script!

The chmod +x command sets the executable bit so that Bash (or any shell) knows it can run the file as a program.

Exit Codes

Every command and script returns an exit status stored in $?:

./hello.sh
echo $?    # Prints the previous command's exit status
Output:
0

An exit code of 0 indicates success; anything else signals an error.

Environment Variables

Bash stores key information about the current session in environment variables like $USER, $HOME, and $PATH. You can view them with printenv or env.

echo $USER
echo $HOME
echo $PATH

Scripts inherit the environment of the process that launches them. You can also define variables within a script:

#!/usr/bin/env bash
name="Alice"
echo "Hello, $name"
Output:
Hello, Alice

What to Remember

  • Start every script with a shebang.
  • Use chmod +x to make scripts executable.
  • Check $? to verify success or failure.
  • Environment variables pass configuration between processes.

3. Variables and Expansion

Variables let you store data and reuse it. In Bash, variables are dynamically typed โ€” they can hold strings, numbers, or the output of commands.

Defining Variables

name="Alice"
greeting="Hello, $name!"
echo $greeting
Output:
Hello, Alice!

Variable Expansion

Use curly braces ${ } to clearly define variable boundaries:

word="world"
echo "Hello, ${word}!"

Bash supports several forms of expansion:

  • ${var:-default} โ€” Use a default value if var is unset or null.
  • ${var:=default} โ€” Assign a default value if var is unset or null.
  • ${var:+alt} โ€” Use alt if var is set.
  • ${#var} โ€” Length of the variableโ€™s value.

Command Substitution

You can assign the output of a command to a variable:

today=$(date +%A)
echo "Today is $today"
Output:
Today is Tuesday

Quoting

Single and double quotes behave differently:

  • 'single quotes' โ€” treat everything literally.
  • "double quotes" โ€” allow variable and command expansion.
name="Alice"
echo 'Hello $name'   # Literal
echo "Hello $name"   # Expanded
Output:
Hello $name
Hello Alice

Read Input

You can prompt users for input using read:

read -p "Enter your name: " username
echo "Welcome, $username!"

IFS (Internal Field Separator)

IFS controls how Bash splits strings:

IFS=',' read -r name age city <<< "Alice,30,Paris"
echo "$name - $age - $city"
Output:
Alice - 30 - Paris

What to Remember

  • Bash variables are dynamically typed and case-sensitive.
  • Always quote variables to avoid word splitting.
  • Use ${ } for clear expansion boundaries.
  • IFS controls input splitting.

4. Arithmetic and Substitution

Bash supports integer arithmetic directly using $(( )) or the let command.

a=5
b=3
sum=$((a + b))
echo "Sum: $sum"
Output:
Sum: 8

You can increment or decrement variables easily:

((a++))
((b--))
echo "a=$a, b=$b"

Command substitution lets you embed command outputs within other commands:

echo "Current directory: $(pwd)"

What to Remember

  • Use $(( )) for arithmetic.
  • let also performs integer math.
  • Always quote $(...) when embedding command output.

5. Conditionals

Conditionals allow scripts to make decisions. Bash uses if, elif, else, and case to execute commands depending on conditions.

Basic if Statement

if [ "$USER" = "root" ]; then
  echo "You are root!"
else
  echo "You are not root."
fi
Output:
You are not root.

Comparison Operators

TypeOperatorDescription
Numeric-eq, -ne, -lt, -le, -gt, -geCompare numbers
String=, !=, -z, -nCompare strings or test length
File-f, -d, -e, -r, -w, -xCheck file properties

Compound Conditions

if [[ $age -ge 18 && $country == "UK" ]]; then
  echo "Eligible voter"
fi

Case Statements

day=$(date +%a)
case $day in
  Mon) echo "Start of week";;
  Fri) echo "Weekend soon!";;
  Sat|Sun) echo "It's the weekend!";;
  *) echo "Midweek";;
esac

What to Remember

  • Single brackets use POSIX syntax; double brackets are Bash-specific.
  • Use && and || for logical operations.
  • case handles multiple pattern matches neatly.

6. Loops

Loops let you repeat actions automatically. Bash supports for, while, and until loops.

For Loop

for i in 1 2 3; do
  echo "Iteration $i"
done
Output:
Iteration 1
Iteration 2
Iteration 3

While Loop

count=1
while [ $count -le 3 ]; do
  echo "Count: $count"
  ((count++))
done
Output:
Count: 1
Count: 2
Count: 3

Reading Files with Loops

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

Until Loop

x=1
until [ $x -gt 3 ]; do
  echo "x=$x"
  ((x++))
done

What to Remember

  • for iterates over lists; while repeats while true.
  • until repeats until condition becomes true.
  • Redirect input with < to read files line by line safely.

7. Arrays and Associative Arrays

Bash supports indexed arrays and associative (key-value) arrays.

Indexed Arrays

fruits=("apple" "banana" "cherry")
echo ${fruits[1]}         # banana
echo ${#fruits[@]}        # number of elements
echo ${fruits[@]}         # all elements

Looping Through Arrays

for fruit in "${fruits[@]}"; do
  echo "I like $fruit"
done

Associative Arrays

declare -A capitals
capitals[France]="Paris"
capitals[Japan]="Tokyo"

for country in "${!capitals[@]}"; do
  echo "$country โ†’ ${capitals[$country]}"
done
Output:
France โ†’ Paris
Japan โ†’ Tokyo

Array Slicing

echo "${fruits[@]:1:2}"  # elements 1 and 2

What to Remember

  • Use () to define arrays.
  • ${array[@]} expands to all elements.
  • Associative arrays require declare -A.

8. Input, Output, and Redirection

Every process in Linux, including your Bash scripts, communicates through three streams:

  • stdin (0) โ€” Standard input
  • stdout (1) โ€” Standard output
  • stderr (2) โ€” Standard error

Redirection lets you control where these streams go.

Redirecting Output

echo "Hello" > hello.txt   # Overwrite
echo "World" >> hello.txt  # Append

Redirecting Input

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

Redirecting Errors

ls /no/such/path 2> errors.log

Combine stdout and stderr into one file:

command > all.log 2>&1

Here Documents

Useful for feeding multi-line input:

cat <<EOF > story.txt
Once upon a time,
in a shell far, far away...
EOF

Here Strings

grep "root" <<< "root:x:0:0:root:/root:/bin/bash"

What to Remember

  • > overwrites, >> appends, 2> redirects errors.
  • < reads input from a file.
  • <<EOF creates a here-document.

9. String Manipulation

Strings are central to shell scripting โ€” paths, messages, filenames, and command outputs are all text. Bash includes several expansion operators for editing strings without external tools.

Substring and Length

text="HelloWorld"
echo ${#text}        # Length
echo ${text:0:5}     # Substring
Output:
10
Hello

Pattern Removal

file="report.txt"
echo ${file%.txt}    # Remove suffix
echo ${file#rep}     # Remove prefix

Replacement

word="banana"
echo ${word/na/NA}   # First match
echo ${word//na/NA}  # All matches

Case Conversion

item="Laptop"
echo ${item^^}
echo ${item,,}
Output:
LAPTOP
laptop

What to Remember

  • Parameter expansion allows trimming and replacing strings quickly.
  • ${#var} gives string length.
  • ${var,,} and ${var^^} change case.

10. printf and Formatting

printf provides predictable, formatted output โ€” unlike echo, it never adds extra newlines or misinterprets escape sequences.

printf "Name: %s\\nAge: %d\\n" "Alice" 30
Output:
Name: Alice
Age: 30

Alignment and Width

printf "%-10s %-10s\\n" Name Country
printf "%-10s %-10s\\n" Alice France
printf "%-10s %-10s\\n" Bob   Japan
Output:
Name       Country
Alice      France
Bob        Japan

Numbers and Formatting

pi=3.14159
printf "Pi: %.2f\\n" $pi

What to Remember

  • printf is more consistent than echo.
  • Use format specifiers for alignment and numeric precision.
  • Escape newlines with \\n.

11. Error Handling

Error handling in Bash ensures your script behaves predictably when things go wrong. By default, Bash continues executing after an error, which can lead to data corruption or incomplete operations. You can control this with built-in options.

set -e, -u, -o pipefail

#!/usr/bin/env bash
set -euo pipefail

echo "Step 1"
command_that_may_fail
echo "Step 2"

Hereโ€™s what each option means:

  • -e: Exit the script when a command fails (non-zero exit code).
  • -u: Treat unset variables as errors.
  • -o pipefail: Makes a pipeline fail if any command in it fails.

Trapping Errors

You can catch signals and handle cleanup using trap:

#!/usr/bin/env bash
trap 'echo "An error occurred at line $LINENO"; exit 1' ERR
false   # Triggers ERR
Output:
An error occurred at line 3

Custom Exit Codes

Return specific exit codes from your scripts:

#!/usr/bin/env bash
if [[ -z "$1" ]]; then
  echo "Usage: $0 filename"
  exit 1
fi

What to Remember

  • set -euo pipefail makes scripts safer.
  • Use trap to clean up temporary files or print error messages.
  • Exit codes communicate success or failure to other programs.

12. Debugging

Debugging Bash scripts can be tricky because errors may not always appear where they occur. Bash provides several tools to help identify problems.

Run with -x

bash -x script.sh

This prints each command before itโ€™s executed.

Use set -x and set +x

You can enable and disable tracing within a script:

set -x
echo "Debugging this section"
set +x

Print Variable States

echo "Value of PATH: $PATH"
echo "Current line: $LINENO"

Dry Runs

You can preview command actions without executing them by echoing them first:

echo "Would delete file: $file"

What to Remember

  • Use -x or set -x for tracing.
  • Print important variables to inspect state.
  • Temporarily comment out risky commands when testing.

13. Advanced Techniques

Once youโ€™re comfortable with Bash basics, you can combine commands, functions, and process control for more powerful scripts.

Functions

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

Returning Values

Bash functions return numeric codes. To return strings, use echo:

get_date() {
  echo $(date +%Y-%m-%d)
}
today=$(get_date)
echo "Today: $today"

Subshells

(cd /tmp && ls)

Parentheses ( ) create a subshell โ€” a new Bash process where variables and directory changes donโ€™t affect the parent shell.

Command Grouping

{
  echo "Start"
  ls /tmp
  echo "End"
}

Parallel Execution

cmd1 &
cmd2 &
wait
echo "Both finished!"

What to Remember

  • Functions organize reusable code.
  • Subshells isolate environments.
  • Group commands for clarity and reuse.
  • Use & for background jobs and wait for synchronization.

14. Best Practices

  • Always start scripts with #!/usr/bin/env bash.
  • Use set -euo pipefail for reliability.
  • Quote all variable expansions: "$var".
  • Prefer [[ ]] over [ ].
  • Use functions to keep code modular.
  • Comment your code and handle errors gracefully.
  • Use shellcheck (sudo apt install shellcheck) to lint scripts.

15. Conclusion

Youโ€™ve now explored the essential and advanced aspects of Bash โ€” from running your first script to handling errors, using arrays, debugging, and writing modular, safe code. Bash remains one of the most flexible and powerful tools for system automation and scripting. The more you experiment, the more natural it becomes to think in Bash.

At this point, you can automate workflows, process files, build utilities, and even combine Bash with other languages and tools for full-stack automation.

Remember that practice is key: take small repetitive tasks and rewrite them as Bash scripts. Youโ€™ll quickly see patterns emerge and gain fluency in the language of the shell.

Glossary

Shebang
The first line in a script (e.g., #!/usr/bin/env bash) that tells the system which interpreter to use.
Subshell
A new shell process launched from within another shell; it inherits environment variables but runs independently.
Expansion
The process where Bash replaces variables, commands, or patterns with their values before execution.
Redirection
Changing where input comes from or output goes to (files, pipes, etc.).
Pipe
A mechanism (|) to pass the output of one command as input to another.
Exit Status
A numeric code returned by a command: 0 means success, non-zero indicates an error.
Parameter Expansion
Modifying or retrieving the value of a variable using syntax like ${var}.
IFS (Internal Field Separator)
A variable that defines how Bash splits strings into words; default is whitespace.
Array
An ordered list of elements accessed by index.
Associative Array
A key-value mapping similar to dictionaries in other languages.
Trap
A command used to catch and respond to system signals or script errors.
Function
A named block of code that performs a specific task and can be reused.
Loop
A control structure that repeats a block of code while a condition is true.
Conditional
A statement that executes different code depending on whether a test evaluates to true or false.
Brace Expansion
Generates arbitrary strings, e.g., echo file{1..3}.txt.
Glob
Pattern used to match filenames (e.g., *.txt).
Here Document
A block of text fed into a commandโ€™s standard input using <<EOF.
POSIX
A standard that defines how Unix-like systems behave and interact with shells and utilities.
Shellcheck
A linting tool that analyzes shell scripts for errors and suggests improvements.
Pipeline
A series of commands connected by pipes (|) where the output of one command feeds the next.

Further Reading and Next Steps

  • Learning awk: Master pattern scanning and field processing for structured text data.
  • Mastering sed: Learn stream editing and complex text transformations using regular expressions.
  • Exploring grep: Perform advanced searching and filtering across files and command output.
  • Working with jq: Parse and manipulate JSON efficiently from the command line.
  • Shell scripting in CI/CD: Integrate Bash scripts into continuous integration workflows for automation.

Each of these tools builds upon your Bash knowledge and opens the door to mastering the wider Unix command-line ecosystem.

Smart reads for curious minds

We donโ€™t spam! Read more in our privacy policy