Table of Contents
- What is Bash Scripting?
- Why Automate with Bash?
- Prerequisites
- Anatomy of a Bash Script
- Writing Your First Bash Script
- Variables and Data Types
- Control Structures: If-Else Statements
- Loops: For and While
- Functions
- Input/Output Redirection
- Error Handling
- Practical Automation Examples
- Best Practices
- Conclusion & Next Steps
- References
What is Bash Scripting?
Bash (Bourne Again SHell) is a Unix shell and command language widely used as the default shell in Linux and macOS. A Bash script is a plain text file containing a sequence of Bash commands. When executed, the shell reads and runs these commands in order, automating tasks that would otherwise require manual input.
Unlike compiled languages (e.g., C++), Bash scripts are interpreted—meaning the shell executes commands line-by-line without prior compilation. This makes scripting fast to write and easy to test.
Why Automate with Bash?
Automating with Bash offers several key benefits:
- Time Savings: Eliminate repetitive tasks (e.g., daily backups, log cleanup).
- Consistency: Ensure tasks run the same way every time (no human error).
- Scalability: Manage hundreds of files or systems with a single script.
- Accessibility: Bash is preinstalled on Linux/macOS, so no extra tools are needed.
Common use cases include:
- Scheduling backups.
- Monitoring system resources (CPU, memory).
- Cleaning up temporary files.
- Deploying code to servers.
- Generating reports from logs.
Prerequisites
Before diving in, you’ll need:
- Basic Linux Command-Line Knowledge: Familiarity with commands like
ls,cd,cp,mkdir, andchmod. - A Text Editor: Use
nano,vim, VS Code, or any editor to write scripts (we’ll usenanofor simplicity). - File Permissions: Understanding how to make files executable with
chmod.
Anatomy of a Bash Script
A typical Bash script has three core components:
1. Shebang Line
The first line of a script, #!/bin/bash, tells the system to use the Bash interpreter to run the script. Without this, the system may default to a different shell (e.g., sh), which lacks some Bash features.
2. Comments
Lines starting with # (excluding the shebang) are comments. They explain the script’s purpose, making it easier to read and maintain:
#!/bin/bash
# This is a comment explaining the script
echo "Hello, World!" # This line prints a message
3. Commands
The body of the script contains Linux commands (e.g., echo, cp, tar) executed in sequence.
Writing Your First Bash Script
Let’s create a simple “Hello World” script to get started.
Step 1: Create the Script File
Open a terminal and use nano to create a new file named hello.sh:
nano hello.sh
Step 2: Add Script Content
Type the following into the editor:
#!/bin/bash
# My first Bash script
echo "Hello, World!"
#!/bin/bash: Shebang line (required).# My first Bash script: A comment.echo "Hello, World!": Command to print text to the terminal.
Step 3: Save and Exit
Press Ctrl+O to save, then Ctrl+X to exit nano.
Step 4: Make the Script Executable
By default, the script is not executable. Use chmod to grant execution permissions:
chmod +x hello.sh
Step 5: Run the Script
Execute the script with:
./hello.sh
You’ll see:
Hello, World!
Congratulations! You’ve written and run your first Bash script.
Variables and Data Types
Variables store data for reuse in scripts. Bash has no strict data types (all variables are treated as strings), but you can work with numbers, text, and arrays.
Declaring Variables
Use variable_name=value (no spaces around =):
name="Alice"
age=30
Accessing Variables
Prefix the variable name with $ to access its value:
echo "Name: $name" # Output: Name: Alice
echo "Age: $age" # Output: Age: 30
Environment Variables
Bash provides built-in environment variables for system info (e.g., $HOME for your home directory, $USER for your username):
echo "Home: $HOME" # Output: Home: /home/alice
echo "User: $USER" # Output: User: alice
User Input
Use read -p "Prompt: " variable to get input from the user:
#!/bin/bash
read -p "Enter your name: " name
echo "Hello, $name!"
Run it:
./greet.sh
Enter your name: Bob
Hello, Bob!
Control Structures: If-Else Statements
Control structures let you run commands conditionally. The most common is the if-else statement.
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 are critical! Always add spaces after [ and before ].
Example: Check if a File Exists
#!/bin/bash
read -p "Enter a filename: " filename
if [ -f "$filename" ]; then # -f checks if the file exists and is a regular file
echo "$filename exists!"
elif [ -d "$filename" ]; then # -d checks if it's a directory
echo "$filename is a directory!"
else
echo "$filename does NOT exist."
fi
Test it with a real file (e.g., hello.sh) and a fake file (e.g., nonexistent.txt).
Example: Compare Numbers
Use -eq (equal), -ne (not equal), -gt (greater than), -lt (less than):
#!/bin/bash
read -p "Enter a number: " num
if [ $num -gt 10 ]; then
echo "$num is greater than 10!"
elif [ $num -eq 10 ]; then
echo "$num equals 10!"
else
echo "$num is less than 10!"
fi
Loops: For and While
Loops automate repetitive tasks, like iterating over files or running commands multiple times.
For Loops
Iterate over a list (e.g., filenames, numbers):
Example 1: List Text Files
#!/bin/bash
echo "Text files in current directory:"
for file in *.txt; do # Iterate over all .txt files
echo "- $file"
done
Example 2: Count to 5
#!/bin/bash
for i in {1..5}; do # {1..5} generates 1 2 3 4 5
echo "Count: $i"
done
While Loops
Run commands until a condition is false:
Example: Countdown from 5
#!/bin/bash
count=5
while [ $count -gt 0 ]; do
echo $count
count=$((count - 1)) # Decrement count by 1
sleep 1 # Pause for 1 second
done
echo "Blast off!"
Functions
Functions let you reuse blocks of code. Define them once, call them anywhere in the script.
Syntax
function_name() {
# Commands here
}
Example: Greeting Function
#!/bin/bash
greet() {
local name=$1 # $1 is the first argument passed to the function
echo "Hello, $name!"
}
read -p "Enter your name: " username
greet "$username" # Call the function with the username as an argument
Note: Use local to limit variable scope to the function (avoids overwriting global variables).
Input/Output Redirection
Redirection lets you send command output to files or read input from files instead of the terminal.
Output Redirection
>: Overwrite a file with output (e.g.,echo "Hi" > file.txt).>>: Append output to a file (e.g.,echo "Again" >> file.txt).
Example: Save a list of files to file_list.txt:
ls -l > file_list.txt # Overwrites file_list.txt
echo "New line" >> file_list.txt # Adds to the end
Input Redirection
<: Read input from a file (e.g., sort < file.txt sorts the file’s contents).
Pipes (|)
Send output of one command to another (e.g., grep to filter results):
ls -l | grep ".sh" # List only .sh files in the current directory
Error Handling
Bash scripts can fail silently, so adding error handling ensures you catch issues early.
Exit Codes
Every command returns an exit code:
0: Success.- Non-zero (e.g.,
1,2): Failure (code varies by command).
Check the exit code of the last command with $?:
ls nonexistent.txt
echo "Exit code: $?" # Output: Exit code: 2 (failure)
set -e: Exit on Error
Add set -e at the top of your script to make it exit immediately if any command fails:
#!/bin/bash
set -e # Exit on first error
echo "This runs."
ls nonexistent.txt # Fails, script exits here
echo "This will NOT run."
Check Command Success in if Statements
#!/bin/bash
if ls nonexistent.txt; then
echo "Command succeeded!"
else
echo "Command failed with exit code $?."
fi
Practical Automation Examples
Let’s build real-world scripts to automate common tasks.
Example 1: Automated Backup Script
Backup a directory to a compressed .tar.gz file with a timestamp:
#!/bin/bash
set -e # Exit on error
SOURCE="/home/user/documents" # Directory to back up
DEST="/media/backup" # Backup destination
TIMESTAMP=$(date +%Y%m%d_%H%M%S) # e.g., 20240520_143022
FILENAME="backup_$TIMESTAMP.tar.gz"
# Create backup
echo "Creating backup: $DEST/$FILENAME"
tar -czf "$DEST/$FILENAME" "$SOURCE"
echo "Backup completed successfully!"
tar -czf:c(create),z(compress with gzip),f(specify filename).- Run with
./backup.sh, or schedule it withcronfor daily backups.
Example 2: Log Cleaner
Delete log files older than 7 days:
#!/bin/bash
set -e
LOG_DIR="/var/log"
DAYS=7 # Delete files older than 7 days
echo "Cleaning logs in $LOG_DIR older than $DAYS days..."
find "$LOG_DIR" -name "*.log" -mtime +$DAYS -delete
echo "Log cleanup complete!"
find: Searches for files.-name "*.log": Match.logfiles.-mtime +7: Modified more than 7 days ago.-delete: Delete matching files.
Best Practices
To write reliable, maintainable scripts:
- Use Descriptive Names: Name scripts/functions clearly (e.g.,
backup_documents.shinstead ofscript.sh). - Add Comments: Explain why (not just what) the code does.
- Test in Stages: Test small parts before combining them.
- Handle Edge Cases: Check for empty directories, missing files, or invalid inputs.
- Quote Variables: Use
"$variable"to handle spaces in filenames (e.g.,file="my doc.txt"). - Avoid Hardcoding Paths: Use variables (e.g.,
SOURCE="/home/user"instead of hardcoding).
Conclusion & Next Steps
Bash scripting is a powerful tool for automating Linux tasks, from simple one-liners to complex workflows. In this guide, you learned:
- How to write and run Bash scripts.
- Variables, control structures, loops, and functions.
- Input/output redirection and error handling.
- Practical automation examples (backups, log cleaning).
Next Steps
- Learn Advanced Tools:
awk(text processing),sed(stream editing), andcron(scheduling scripts). - Debugging: Use
set -xto print commands as they run (addset -xto your script). - Explore More Examples: Automate system monitoring, user management, or deployment pipelines.
References
- GNU Bash Manual
- Linux Man Pages (run
man bashin the terminal). - ShellScript.sh – Tutorials and examples.
- Book: Learning the Bash Shell by Cameron Newham (O’Reilly).
Happy scripting! 🚀