Bash scripting is surprisingly powerful for network automation because it lets you treat network operations as simple text manipulation.
Let’s look at how to check if a remote service is actually listening on its port. We’ll use nc (netcat) for this, the "Swiss Army knife" of networking.
#!/bin/bash
HOST="example.com"
PORT="80"
if nc -z -w 2 "$HOST" "$PORT" > /dev/null 2>&1; then
echo "$HOST:$PORT is reachable."
else
echo "$HOST:$PORT is NOT reachable."
fi
This script checks if example.com is responding on port 80. The -z flag tells nc to just report the status of the connection, not to send any data. The -w 2 sets a 2-second timeout. If nc can establish a connection within that time, it exits with status 0, which our if statement interprets as success. Redirecting stdout and stderr to /dev/null keeps the output clean.
This basic check is the foundation for more complex automation. You can build on this to create a script that checks a list of services across multiple hosts, alerting you only when something is actually down.
Here’s a more elaborate example that checks a list of hosts and ports from a file:
#!/bin/bash
SERVICE_FILE="services.txt"
LOG_FILE="service_check.log"
echo "--- Starting service check $(date) ---" >> "$LOG_FILE"
while IFS= read -r line || [[ -n "$line" ]]; do
# Skip empty lines and comments
[[ -z "$line" || "$line" =~ ^# ]] && continue
# Expecting format: HOST:PORT
IFS=':' read -r HOST PORT <<< "$line"
if [[ -z "$HOST" || -z "$PORT" ]]; then
echo "Skipping malformed line: $line" >> "$LOG_FILE"
continue
fi
if nc -z -w 2 "$HOST" "$PORT" > /dev/null 2>&1; then
echo "$HOST:$PORT is UP" >> "$LOG_FILE"
else
echo "$HOST:$PORT is DOWN" >> "$LOG_FILE"
# Add alerting mechanism here, e.g., send an email
# mail -s "Service Down: $HOST:$PORT" admin@example.com <<< "Service $HOST:$PORT is not responding."
fi
done < "$SERVICE_FILE"
echo "--- Service check finished $(date) ---" >> "$LOG_FILE"
The services.txt file would look something like this:
# Web servers
example.com:80
internal.net:8080
# Database
db.internal.net:5432
This script reads each HOST:PORT pair from services.txt. For each entry, it attempts a zero-I/O connection using nc. If nc fails (non-zero exit code), it logs the service as "DOWN" and could trigger an alert. The IFS= read -r line || [[ -n "$line" ]] construct is a robust way to read lines from a file, handling potential trailing newlines. The IFS=':' read -r HOST PORT <<< "$line" splits the line into host and port variables.
The real power comes from combining these simple checks with other Bash utilities. You can pipe the output of these checks into grep to filter for failures, or use awk to generate reports. For instance, to quickly see just the services that are down:
grep "is DOWN" service_check.log
You can also use ping to check host reachability before even bothering with port checks. A common pattern is to first ping the host, and only if it’s up, then try nc for the specific port.
#!/bin/bash
HOST="example.com"
PORT="80"
if ping -c 1 -W 1 "$HOST" > /dev/null 2>&1; then
echo "$HOST is reachable via ping. Checking port $PORT..."
if nc -z -w 2 "$HOST" "$PORT" > /dev/null 2>&1; then
echo "$HOST:$PORT is UP"
else
echo "$HOST:$PORT is DOWN"
fi
else
echo "$HOST is NOT reachable via ping."
fi
Here, ping -c 1 -W 1 sends a single ICMP echo request (-c 1) and waits for 1 second for a response (-W 1). This adds a layer of diagnostics: is the host itself dead, or is just the service on that host unresponsive?
The counterintuitive part of using Bash for network tasks is how little you actually need to know about complex protocols. You’re essentially just scripting the behavior of tools like ping, nc, curl, wget, and ssh, which already understand the underlying TCP/IP protocols. Bash provides the glue to orchestrate these tools based on their exit codes and standard output, making it feel like you’re directly manipulating network state when you’re really just reading and writing text.
The true elegance lies in how Bash’s string manipulation and conditional logic allow you to abstract away the network specifics. For example, you can parse the output of nmap or ss to get a comprehensive view of network connections and then use Bash to act on that information.
The next step in automating network tasks with Bash involves integrating with APIs or more complex configuration management tools.