Linux Bash Scripting
Learn how to write practical Bash scripts with variables, conditionals, loops, functions, arrays, redirection, traps, and exit codes.
Why Bash Scripting Matters
Bash scripting is where Linux command-line knowledge becomes automation. A Bash script can validate environment state, deploy an application, rotate logs, back up files, or glue together tools that do one job each.
Bash is not the best language for every task, but it is excellent for lightweight automation that lives close to the operating system.
Starting with the Shebang
A script usually begins with a shebang line that tells the system which interpreter to use.
#!/usr/bin/env bash
Save the script, make it executable, and run it:
chmod +x deploy.sh
./deploy.sh
Variables and Positional Parameters
Variables store values.
name="devops"
env="production"
echo "$name"
Bash also provides positional parameters for command-line arguments.
echo "$1"
echo "$2"
echo "$#"
$1is the first argument$2is the second argument$#is the number of arguments$@represents all arguments
Example:
./backup.sh /var/log nginx
Inside the script, $1 might be /var/log and $2 might be nginx.
Conditionals with if, elif, and else
Use conditionals to make decisions.
if [ -f /etc/nginx/nginx.conf ]; then
echo "Nginx config exists"
elif [ -d /etc/nginx ]; then
echo "Nginx directory exists"
else
echo "Nginx not installed"
fi
Common test operators:
-ffile exists-ddirectory exists-zstring is empty-nstring is not empty
Loops: for and while
A for loop repeats over a list.
for host in app1 app2 app3; do
echo "Checking $host"
done
A while loop repeats while a condition is true.
count=1
while [ "$count" -le 3 ]; do
echo "Attempt $count"
count=$((count + 1))
done
Loops are common in operations scripts that process files, services, or hosts.
Functions
Functions group logic into reusable units.
log_info() {
echo "[INFO] $1"
}
check_file() {
if [ -f "$1" ]; then
echo "Found: $1"
else
echo "Missing: $1"
fi
}
Then call them:
log_info "Starting check"
check_file /etc/hosts
Functions improve readability and reduce duplication.
Arrays and String Operations
Bash supports arrays.
services=(nginx sshd docker)
echo "${services[0]}"
echo "${services[@]}"
Basic string operations are also useful.
filename="app.log"
echo "${filename%.log}"
echo "${filename/app/service}"
These features help with small automation tasks without calling external tools for everything.
Exit Codes
Every command returns an exit code. 0 usually means success. Non-zero means failure.
mkdir testdir
echo $?
In scripts, you often check exit codes directly or stop early on failure.
cp config.yaml config.yaml.bak || exit 1
You can also end your own script with a chosen exit code:
exit 0
exit 1
Standard Input, Output, and Error
Bash scripts interact with three standard streams:
- stdin: input stream
- stdout: normal output
- stderr: error output
Example:
echo "normal message"
echo "error message" >&2
Redirection lets you control where output goes.
./script.sh > output.log 2> error.log
./script.sh < input.txt
This is important when integrating scripts into CI pipelines or scheduled jobs.
Cleaning Up with trap
trap lets you run cleanup code when a script exits or receives a signal.
cleanup() {
echo "Cleaning up"
}
trap cleanup EXIT
This is useful for removing lock files, stopping background jobs, or printing final status messages.
Tip:
trapis a simple way to make scripts safer and more professional.
Practical Example: Argument Validation Script
#!/usr/bin/env bash
if [ "$#" -lt 1 ]; then
echo "Usage: $0 <directory>" >&2
exit 1
fi
target_dir="$1"
if [ ! -d "$target_dir" ]; then
echo "Directory not found: $target_dir" >&2
exit 2
fi
echo "Listing files in $target_dir"
ls -lah "$target_dir"
This script demonstrates positional parameters, conditionals, stderr, and exit codes.
Practical Example: Service Health Check Script
#!/usr/bin/env bash
services=(nginx sshd docker)
for service in "${services[@]}"; do
if systemctl is-active --quiet "$service"; then
echo "$service is running"
else
echo "$service is not running" >&2
fi
done
This type of script is realistic for server health reporting.
Best Practices for Bash Scripts
- quote variables like
"$1"to avoid word-splitting bugs - keep scripts focused and readable
- use functions for repeated logic
- return meaningful exit codes
- send errors to stderr when appropriate
- test scripts with both expected and unexpected input
Bash becomes much easier when you treat it as structured automation, not just a long list of commands.
Test Your Understanding
Let's see how well you understood the concepts! These exercises will help reinforce what you just learned.
Exercise 1: Counting script arguments
Question: In the tutorial, what does $# represent inside a Bash script?
Exercise 1: Counting script arguments
Identify what the special parameter $# contains in Bash.
Exercise 2: Writing to stderr
Scenario: Your script wants to print a usage message when no directory argument is provided.
Question: Why does the example use >&2 for that message?
Exercise 2: Writing to stderr
Choose why a Bash script redirects an error message to file descriptor 2.
Exercise 3: Registering exit cleanup
Question: What does trap cleanup EXIT do in the lesson's example?
Exercise 3: Registering exit cleanup
Identify what the trap statement accomplishes when the script exits.