Bash scripting for beginners part 3 banner
Bash beginner series · Part 3

Bash Scripting for Beginners: Loops, Functions and Real Admin Scripts

Part 3 turns small scripts into useful admin tools. You will learn for loops, while loops, arrays, functions, logging and practical scripts for services, disk usage and DNS checks.

On this page
Loops

For loops

A for loop repeats commands for each item in a list.

for file in *.log; do
  echo "$file"
done

Arrays are a clean way to store lists.

SERVICES=("nginx" "mysql" "sshd")

for SERVICE in "${SERVICES[@]}"; do
  echo "$SERVICE"
done
Loops

Read a file line by line with while

This pattern is useful when reading a list of domains, users or paths.

while IFS= read -r DOMAIN; do
  echo "Checking $DOMAIN"
done < domains.txt
Functions

Bash functions

Functions let you reuse blocks of logic.

check_service() {
  local service="$1"

  if systemctl is-active --quiet "$service"; then
    echo "[OK] $service is running"
  else
    echo "[WARN] $service is not running"
  fi
}
Logging

Add simple logging to scripts

log_msg() {
  echo "[$(date -Is)] $*"
}

log_msg "Starting checks"

To log to a file as well as the terminal, use tee.

log_msg "Backup completed" | tee -a /var/log/my-script.log
Safer scripts

Using set -euo pipefail carefully

You will often see this near the top of Bash scripts:

set -euo pipefail
OptionMeaning
-eExit if a command fails.
-uTreat unset variables as an error.
-o pipefailFail a pipeline if any command in it fails.
This can make scripts safer, but it can also surprise beginners. Add it once you understand how your script handles expected failures.
Example script

Script 1: check multiple services

#!/usr/bin/env bash

SERVICES=("nginx" "mysql" "sshd")

check_service() {
  local service="$1"

  if systemctl is-active --quiet "$service"; then
    echo "[OK] $service is running"
  else
    echo "[WARN] $service is not running"
  fi
}

for service in "${SERVICES[@]}"; do
  check_service "$service"
done
$ ./check-services.sh
[OK] nginx is running
[WARN] mysql is not running
[OK] sshd is running
Line by line

What the multiple services script is doing

LineMeaning
SERVICES=("nginx" "mysql" "sshd")Creates a Bash array containing service names.
check_service() { ... }Defines a reusable function.
local service="$1"Stores the function's first argument in a local variable.
for service in "${SERVICES[@]}"Loops safely through every item in the array.
check_service "$service"Runs the function for each service.
Example script

Script 2: warn when disk usage is high

#!/usr/bin/env bash

THRESHOLD=85
MOUNT="/"

usage="$(df "$MOUNT" | awk 'NR==2 {gsub(/%/,"",$5); print $5}')"

if [ "$usage" -ge "$THRESHOLD" ]; then
  echo "[WARN] Disk usage on $MOUNT is ${usage}%"
  exit 1
else
  echo "[OK] Disk usage on $MOUNT is ${usage}%"
  exit 0
fi
$ ./check-disk.sh
[OK] Disk usage on / is 55%

For deeper disk checks, use the Linux High Disk Usage Troubleshooting Guide.

Example script

Script 3: check DNS for multiple domains

Create a file named domains.txt:

example.com
commandlinequiz.com
example.org

Then create the script:

#!/usr/bin/env bash

while IFS= read -r DOMAIN; do
  [ -z "$DOMAIN" ] && continue
  echo "== $DOMAIN =="
  dig +short "$DOMAIN"
  echo
done < domains.txt
$ ./check-dns.sh
== example.com ==
93.184.216.34

== commandlinequiz.com ==
104.21.10.123
172.67.150.45

== example.org ==
93.184.216.34

For more DNS examples, see the dig command guide.

Try it yourself

Practice exercises

Exercise 1: add another service

Add redis or httpd to the SERVICES array and run the script again.

Exercise 2: write output to a log file

Update the service checker so the output is also appended to /tmp/service-check.log.

./check-services.sh | tee -a /tmp/service-check.log

Exercise 3: check domains from a file

Add more domains to domains.txt and confirm your DNS checker loops through each one.

Downloads

Download the example scripts

Final checks

Check scripts before using them on a server

bash -n check-services.sh
shellcheck check-services.sh

When the script changes files or restarts services, test it on a safe machine first. Production servers are not the place for “let’s see what happens”.

Next steps

Where to go next

Admin script pattern

Combine loops and functions for cleaner scripts

Once a script grows beyond a few lines, functions make it easier to read and reuse.

#!/usr/bin/env bash

check_service() {
  local service="$1"

  if systemctl is-active --quiet "$service"; then
    echo "OK: $service is running"
  else
    echo "ERROR: $service is not running"
  fi
}

for service in nginx mariadb sshd; do
  check_service "$service"
done
Example output:
OK: nginx is running
OK: mariadb is running
ERROR: sshd is not running
FAQ

Frequently Asked Questions

When should I use Bash functions?

Use functions when a block of commands has a clear job or needs to be reused.

Can Bash loops call functions?

Yes. A common pattern is to loop through a list and call a function for each item.

How do I keep Bash scripts readable?

Use clear variable names, functions, comments for intent and small sections that do one job.

What should I learn after beginner Bash scripting?

Learn loops, functions, exit codes, logging, cron or systemd timers and safer input handling.

$ practise_next --topic bash

Practise this next

Turn the guide into practice with a related quiz, builder, cheat sheet or learning path.