dotlinux blog

Write Your First Bash Script: A Comprehensive Guide

Bash scripting is a powerful tool for automating tasks, managing systems, and simplifying repetitive workflows on Unix-like operating systems (Linux, macOS, etc.). Whether you’re a developer, system administrator, or just a curious user, learning to write bash scripts can save you time and effort. In this guide, we’ll walk you through creating your first bash script, starting with the basics and gradually building up to more advanced concepts. By the end, you’ll have the skills to write functional scripts and understand best practices for scripting in bash.

2026-01

Table of Contents#

  1. Prerequisites
  2. What is a Bash Script?
  3. Your First Bash Script: "Hello, World!"
  4. Variables in Bash
  5. User Input
  6. Control Structures: If-Else Statements
  7. Loops: For and While
  8. Error Handling
  9. Putting It All Together: A Practical Script
  10. Best Practices for Bash Scripting
  11. Troubleshooting Common Issues
  12. Conclusion
  13. References

Prerequisites#

Before diving in, ensure you have:

  • A Unix-like operating system (Linux, macOS, or WSL on Windows).
  • Basic familiarity with the terminal (e.g., navigating directories with cd, listing files with ls).
  • A text editor (e.g., nano, vim, VS Code, or Sublime Text).
  • Bash installed (check with bash --version; most systems include it by default).

What is a Bash Script?#

A bash script is a text file containing a sequence of commands that the bash shell can execute. It allows you to automate tasks by combining multiple commands into a single file. Scripts are useful for:

  • Automating backups, log rotation, or file cleanup.
  • Running complex workflows (e.g., processing data, deploying code).
  • Simplifying repetitive tasks (e.g., renaming files, checking system status).

Your First Bash Script: "Hello, World!"#

Let’s start with the classic "Hello, World!" example to learn the basics of script structure.

Step 1: Create the Script File#

Open your text editor and create a new file named hello_world.sh. The .sh extension is a convention to indicate a shell script (though not strictly required).

Step 2: Add the Shebang Line#

Every bash script should start with a shebang line, which tells the system which interpreter to use to run the script. For bash, this is:

#!/bin/bash
  • #! is called a "shebang" or "hashbang."
  • /bin/bash is the path to the bash interpreter (verify with which bash).

Step 3: Add Commands#

Below the shebang line, add the command to print "Hello, World!" using echo:

#!/bin/bash
 
# This is a comment (ignored by the shell)
echo "Hello, World!"
  • Comments start with # and help explain the script’s purpose.

Step 4: Make the Script Executable#

By default, the script is just a text file. To run it, you need to make it executable with chmod:

chmod +x hello_world.sh
  • chmod +x grants "execute" permission to the file.

Step 5: Run the Script#

Execute the script using ./ (to specify the current directory):

./hello_world.sh

Output:

Hello, World!

Congratulations! You’ve written and run your first bash script.

Variables in Bash#

Variables store data for reuse in scripts. They help make scripts dynamic and readable.

Defining Variables#

Variables are defined with variable_name=value (no spaces around =):

name="Alice"
age=30

Accessing Variables#

Use $variable_name to access a variable’s value:

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

Command Substitution#

Capture the output of a command into a variable using $(command):

#!/bin/bash
 
current_date=$(date +"%Y-%m-%d")  # Get current date in YYYY-MM-DD format
echo "Today is $current_date"      # Output: Today is 2024-05-20 (example)

User Input#

Use the read command to get input from the user during script execution.

Basic Input#

#!/bin/bash
 
echo "What is your name?"
read name  # Stores user input in the 'name' variable
echo "Hello, $name!"

Prompt with read -p#

Use -p to display a prompt directly:

#!/bin/bash
 
read -p "Enter your name: " name
echo "Welcome, $name!"

Output:

Enter your name: Bob
Welcome, Bob!

Control Structures: If-Else Statements#

If-else statements let you run commands conditionally.

Syntax#

if [ condition ]; then
    # Commands to run if condition is true
elif [ another_condition ]; then
    # Commands if first condition is false, second is true
else
    # Commands if all conditions are false
fi  # Closes the if statement
  • Note: Spaces around [ and ] are required (they’re part of the test command).

Example: Check if a Number is Positive/Negative/Zero#

#!/bin/bash
 
read -p "Enter a number: " num
 
if [ $num -gt 0 ]; then  # -gt = greater than
    echo "$num is positive"
elif [ $num -lt 0 ]; then  # -lt = less than
    echo "$num is negative"
else
    echo "$num is zero"
fi

Output:

Enter a number: -5
-5 is negative

Common Conditions#

OperatorMeaningExample
-eqEqual to[ $a -eq $b ]
-neNot equal to[ $a -ne $b ]
-gtGreater than[ $a -gt $b ]
-ltLess than[ $a -lt $b ]
-geGreater than or equal to[ $a -ge $b ]
-leLess than or equal to[ $a -le $b ]
-fFile exists and is a regular file[ -f "file.txt" ]
-dDirectory exists[ -d "my_dir" ]

Loops: For and While#

Loops repeat commands multiple times.

For Loops: Iterate Over Items#

Syntax: for item in list; do ... done#

#!/bin/bash
 
# Loop through numbers 1-5
for i in {1..5}; do
    echo "Number: $i"
done

Output:

Number: 1
Number: 2
Number: 3
Number: 4
Number: 5

Loop Through Files in a Directory#

#!/bin/bash
 
# List all .txt files in the current directory
echo "Text files in current directory:"
for file in *.txt; do
    echo "- $file"
done

While Loops: Repeat Until a Condition Fails#

Syntax: while [ condition ]; do ... done#

#!/bin/bash
 
count=1
while [ $count -le 5 ]; do
    echo "Count: $count"
    count=$((count + 1))  # Increment count
done

Output:

Count: 1
Count: 2
Count: 3
Count: 4
Count: 5

Error Handling#

Prevent scripts from failing silently with error-handling techniques.

Exit on Error with set -e#

Add set -e at the top of your script to exit immediately if any command fails:

#!/bin/bash
set -e  # Exit on error
 
echo "This command succeeds"
ls non_existent_file.txt  # This fails, so the script exits here
echo "This line will NOT run"

Check Exit Codes#

Every command returns an exit code (0 = success, non-zero = failure). Access it with $?:

#!/bin/bash
 
ls "existing_file.txt"
echo "Exit code: $?"  # Output: 0 (success)
 
ls "non_existent_file.txt"
echo "Exit code: $?"  # Output: 2 (failure)

Putting It All Together: A Practical Script#

Let’s combine variables, user input, if statements, loops, and error handling into a script that analyzes a directory.

Script: directory_analyzer.sh#

#!/bin/bash
set -euo pipefail  # Exit on error, unset variable, or pipeline failure
 
# Greet the user and get their name
read -p "Hello! What's your name? " username
echo "Nice to meet you, $username! Let's analyze a directory."
 
# Get directory path from the user
read -p "Enter the directory path to analyze: " dir_path
 
# Check if the directory exists
if [ ! -d "$dir_path" ]; then
    echo "Error: Directory '$dir_path' does not exist."
    exit 1  # Exit with code 1 (failure)
fi
 
# List files in the directory
echo -e "\nFiles in $dir_path:"
ls -l "$dir_path"
 
# Count total files (excluding directories)
file_count=$(find "$dir_path" -maxdepth 1 -type f | wc -l)
echo -e "\nTotal files in directory: $file_count"
 
# Loop through files and print names
echo -e "\nPrinting filenames:"
for file in "$dir_path"/*; do
    if [ -f "$file" ]; then  # Only process regular files
        echo "- $(basename "$file")"  # Get filename without path
    fi
done
 
echo -e "\nAnalysis complete. Goodbye, $username!"

How It Works:#

  1. Shebang & Error Handling: #!/bin/bash and set -euo pipefail ensure robustness.
  2. User Input: read -p gets the username and directory path.
  3. Condition Check: [ ! -d "$dir_path" ] verifies the directory exists.
  4. Command Substitution: $(find ... | wc -l) counts files.
  5. Loop: Iterates over files and prints names with basename.

Run the Script:#

chmod +x directory_analyzer.sh
./directory_analyzer.sh

Best Practices for Bash Scripting#

  1. Use Comments: Explain complex logic with #.
  2. Meaningful Variables: Use names like user_count instead of x.
  3. Quote Variables: "$variable" prevents errors with spaces in filenames.
  4. Test Scripts: Run incrementally and test edge cases (e.g., empty directories).
  5. Set Permissions: Always chmod +x to make scripts executable.
  6. Shebang Line: Start with #!/bin/bash (not #!/bin/sh unless POSIX compliance is needed).
  7. Avoid Spaces in Filenames: They complicate scripting (use underscores instead).

Troubleshooting Common Issues#

  • "Permission denied": Run chmod +x script.sh to make it executable.
  • "Command not found": Ensure the script’s path is correct (use ./script.sh for the current directory).
  • Syntax Errors: Check for missing fi (if) or done (loops), or spaces around [ ].
  • Variables Not Working: Ensure no spaces around = (e.g., name="Bob" not name = "Bob").

Conclusion#

You’ve learned the fundamentals of bash scripting: creating scripts, variables, user input, control structures, loops, error handling, and best practices. Start small (e.g., automate file backups) and gradually build more complex scripts. The more you practice, the more proficient you’ll become at leveraging bash to simplify your workflow.

References#