Skip to content
Commitpedia
Log in Join & edit

Port check script: test a list of host:port pairs with timeouts

A bash script that tries a TCP connection to each host:port you give it, waits a few seconds at most, and reports OPEN, CLOSED or TIMEOUT so you can tell a firewall from a stopped service.

Drafted with AI from official documentation. Scripts were run in a test environment and repository links verified. Awaiting a human check. Did it work for you? Last edited Outdated?

Edit history of Port check script: test a list of host:port pairs with timeouts: 1 recorded edit
Edit history · 1 edit
Type
Script
Edits
1
Editors
1
First issued
15 Oct 2026
Last edit
15 Oct 2026
Language
bash
Licence
CC0-1.0

What this changes

Read-only: it only opens TCP connections and closes them again; nothing on your machine or the target changes. Each connection shows up as one entry in the target's connection log.

How to undo it

Nothing to undo. If you installed it, remove it with rm ~/bin/portcheck or wherever you copied it.

After a firewall change, a deployment or a network outage, you want one answer per service: can I reach it? This script takes any number of host:port pairs, gives each one a short timeout and prints a result you can read at a glance. It uses only bash and the timeout command, so it runs on any Linux box; on macOS install coreutils once for gtimeout.

The script

#!/usr/bin/env bash
set -uo pipefail

TIMEOUT=${TIMEOUT:-3}

usage() {
  echo "usage: $0 host:port [host:port ...]" >&2
  echo "       $0 -f targets.txt      (one host:port per line, # comments allowed)" >&2
  echo "  TIMEOUT=5 $0 ...            seconds to wait per target (default 3)" >&2
  exit 2
}

if command -v timeout >/dev/null 2>&1; then
  TO=timeout
elif command -v gtimeout >/dev/null 2>&1; then
  TO=gtimeout
else
  echo "need the timeout command (on macOS: brew install coreutils)" >&2
  exit 2
fi

targets=()
if [[ ${1:-} == "-f" ]]; then
  [[ -r ${2:-} ]] || usage
  while read -r line; do
    line=${line%%#*}
    line=${line//[[:space:]]/}
    [[ -n $line ]] && targets+=("$line")
  done < "$2"
else
  targets=("$@")
fi
(( ${#targets[@]} > 0 )) || usage

failed=0
printf '%-40s %-8s %s\n' TARGET RESULT DETAIL
for t in "${targets[@]}"; do
  host=${t%:*}
  port=${t##*:}
  if [[ -z $host || -z $port || ! $port =~ ^[0-9]+$ ]]; then
    printf '%-40s %-8s %s\n' "$t" SKIP "expected host:port"
    continue
  fi
  start=$(date +%s%N 2>/dev/null || date +%s)
  "$TO" "$TIMEOUT" bash -c "exec 3<>/dev/tcp/$host/$port" 2>/dev/null
  rc=$?
  end=$(date +%s%N 2>/dev/null || date +%s)
  if [[ ${#start} -gt 10 ]]; then
    ms=$(( (end - start) / 1000000 ))
    took="${ms} ms"
  else
    took="$(( end - start )) s"
  fi
  case $rc in
    0)   printf '%-40s %-8s %s\n' "$t" OPEN "$took" ;;
    124) printf '%-40s %-8s %s\n' "$t" TIMEOUT "no answer within ${TIMEOUT}s (firewall, wrong address or host down)"; failed=$((failed + 1)) ;;
    *)   printf '%-40s %-8s %s\n' "$t" CLOSED "refused or unreachable after $took (nothing listening, or name did not resolve)"; failed=$((failed + 1)) ;;
  esac
done

echo
if (( failed > 0 )); then
  echo "RESULT: $failed of ${#targets[@]} targets not reachable"
  exit 1
fi
echo "RESULT: all ${#targets[@]} targets reachable"

How to use it

chmod +x portcheck.sh
./portcheck.sh example.com:443 192.0.2.10:22 192.0.2.10:5432
TIMEOUT=5 ./portcheck.sh db.internal:5432

cat > targets.txt <<'EOF'
# production
web1.example.com:443
web1.example.com:22
db1.internal:5432   # PostgreSQL
EOF
./portcheck.sh -f targets.txt
TARGET                                   RESULT   DETAIL
example.com:443                          OPEN     41 ms
192.0.2.10:22                            OPEN     12 ms
192.0.2.10:5432                          CLOSED   refused or unreachable after 11 ms (nothing listening, or name did not resolve)
10.9.9.9:80                              TIMEOUT  no answer within 3s (firewall, wrong address or host down)

RESULT: 2 of 4 targets not reachable

How it works

  • /dev/tcp/HOST/PORT is a bash feature: opening it as a file makes bash connect over TCP. No nc, nmap or telnet needed.
  • timeout 3 bash -c ... kills the attempt after 3 seconds and returns exit code 124, which the script reports as TIMEOUT. A fast failure (connection refused, unknown host) returns another non-zero code, reported as CLOSED. This distinction mirrors the two error messages explained in the fix article in this topic.
  • The exit status is 1 if anything was unreachable, so you can use it in a deployment pipeline or a monitoring check.
  • IPv6 literals need brackets in the host:port form and are not handled; use a DNS name instead.

Official documentation

Did this work for you?

No votes yet. Be the first.

If it did not work, the report form below tells the editors what went wrong.

See also

  • 0266 What is a port? A port is a numbered door on a computer that lets one machine run many network services at the same time. Beginner · Explains an idea · Any system Article DNS, IP addresses & ports 15 Oct 2026
  • 0274 What is DNS? DNS is the internet's phone book: it turns names like example.com into the IP addresses computers actually use. Beginner · Explains an idea · Any system Article DNS, IP addresses & ports 15 Oct 2026
  • 0275 What is an IP address? An IP address is the unique number that identifies a device on a network so data knows where to go. Beginner · Explains an idea · Any system Article DNS, IP addresses & ports 15 Oct 2026
  • 0280 What is a firewall? A firewall is a filter that decides which network connections are allowed in or out of a computer or network. Beginner · Explains an idea · Any system Article Firewalls 15 Oct 2026
  • 0341 DNS, IP addresses and ports explained for beginners An IP address says which machine, a port says which program on it, and DNS turns names into addresses. The three ideas… Beginner · Explains an idea · Linux, macOS Article DNS, IP addresses & ports 15 Oct 2026
  • 0342 Which process is using a port, and how to free it Find the program behind a busy port with ss, lsof or fuser, decide whether to stop it properly or kill it, and… Beginner · Step by step · Linux, macOS Article DNS, IP addresses & ports · Networking & firewalls 15 Oct 2026

Repos in the wild

History

Every saved edit is kept. The plot on the sleeve draws one line per edit. Open any edit to see exactly what changed.

  1. Dominik +4,135 chars

Report a problem

Something wrong, unsafe or copied? Tell the editors.
What is wrong?