Guide Bash-Scripting Advanced

Networking Automation

Automating connectivity checks, port scans, and API calls from Bash using curl, nc, and the standard networking commands.

3 min read

Waiting for a Service to Become Available

#!/usr/bin/env bash
wait_for_port() {
    local host="$1" port="$2" timeout="${3:-30}"
    local elapsed=0
    while ! nc -z "$host" "$port" 2>/dev/null; do
        if [ "$elapsed" -ge "$timeout" ]; then
            echo "Timed out waiting for $host:$port" >&2
            return 1
        fi
        sleep 1
        ((elapsed++))
    done
    echo "$host:$port is now reachable"
}

wait_for_port "db.internal" 5432 60

This pattern is common before starting an application that depends on a database or another service being ready first (a “wait for dependency” script in CI or entrypoints).

HTTP Health Checks

check_health() {
    local url="$1"
    local status
    status=$(curl -o /dev/null -s -w "%{http_code}" "$url")
    if [ "$status" -eq 200 ]; then
        echo "Healthy: $url"
        return 0
    else
        echo "Unhealthy: $url returned $status" >&2
        return 1
    fi
}

check_health "https://api.example.com/health"

Calling a REST API and Parsing JSON

RESPONSE=$(curl -s -X POST https://api.example.com/deployments \
    -H "Authorization: Bearer $API_TOKEN" \
    -H "Content-Type: application/json" \
    -d '{"environment":"production","version":"1.2.3"}')

# jq is the standard tool for parsing JSON in Bash — install it, don't try to grep/sed JSON
DEPLOY_ID=$(echo "$RESPONSE" | jq -r '.id')
STATUS=$(echo "$RESPONSE" | jq -r '.status')

echo "Deployment $DEPLOY_ID status: $STATUS"

Polling an API Until a Condition Is Met

DEPLOY_ID="abc123"
MAX_ATTEMPTS=30

for ((i = 1; i <= MAX_ATTEMPTS; i++)); do
    STATUS=$(curl -s "https://api.example.com/deployments/$DEPLOY_ID" | jq -r '.status')
    echo "Attempt $i: status=$STATUS"

    case "$STATUS" in
        completed) echo "Deployment succeeded"; exit 0 ;;
        failed)    echo "Deployment failed" >&2; exit 1 ;;
    esac
    sleep 10
done
echo "Timed out waiting for deployment to complete" >&2
exit 1

Checking DNS and Connectivity Before Deploying

preflight_checks() {
    echo "Running pre-deployment checks..."

    if ! getent hosts db.internal > /dev/null; then
        echo "DNS resolution failed for db.internal" >&2
        return 1
    fi

    if ! curl -sf -o /dev/null https://registry.example.com; then
        echo "Cannot reach container registry" >&2
        return 1
    fi

    echo "All pre-flight checks passed"
}

preflight_checks || exit 1

Downloading Files With Retries

download_with_retry() {
    local url="$1" output="$2" max_attempts=3
    for ((i = 1; i <= max_attempts; i++)); do
        if curl -sf -o "$output" "$url"; then
            echo "Downloaded successfully on attempt $i"
            return 0
        fi
        echo "Attempt $i failed, retrying..." >&2
        sleep $((i * 2))
    done
    echo "Failed to download after $max_attempts attempts" >&2
    return 1
}

download_with_retry "https://releases.example.com/app-v1.2.3.tar.gz" "app.tar.gz"

Production Considerations

  • Always use curl -sf (silent + fail-on-HTTP-error) in scripts — plain curl returns exit 0 even on a 404/500 response, since the HTTP request itself technically “succeeded.”
  • Use jq for any real JSON parsing — regex/grep-based JSON parsing is fragile and breaks on formatting changes or nested structures.
  • Bound every network retry loop with a maximum attempt count or timeout — an unconditional retry against a permanently-down dependency will hang a deploy/CI pipeline indefinitely.

Quick Interview Answer

“Networking automation in Bash centers on curl for HTTP/API calls (with -sf to correctly fail on HTTP error codes) and nc -z/getent hosts for lower-level connectivity and DNS checks. JSON responses should be parsed with jq, not regex. Common patterns include ‘wait for a dependency to become reachable’ loops before starting an app, and ‘poll an API until a job completes’ loops with a bounded attempt count and exponential-ish backoff.”

Common Mistakes

  • Using plain curl without -f and assuming a non-2xx HTTP response counts as a script failure — it doesn’t, by default.
  • Parsing JSON with grep/sed/awk instead of jq, breaking the moment the API’s formatting changes slightly.
  • Writing an unbounded polling/retry loop against an external service with no timeout or max-attempt cap.

Add More Questions to This Guide

Know a question that should be here? Share it and help the community!

Open Google Form