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?
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/PORTis a bash feature: opening it as a file makes bash connect over TCP. Nonc,nmaportelnetneeded.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:portform 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
- Pi-hole: network-wide ad blocking with your own DNS server pi-hole/pi-hole A DNS server for your home or office network that answers queries for known advertising and tracking domains with nothing, so every device on the network is protected without installing anything on it. GitHub
- CrowdSec: collaborative intrusion prevention that shares blocklists crowdsecurity/crowdsec CrowdSec reads your logs, detects attacks such as brute force and scanning, blocks the source, and shares anonymised reports so that every participant receives a blocklist built from the whole community. GitHub
- Suricata: a network intrusion detection and prevention engine OISF/suricata Suricata inspects network traffic in real time, matches it against signature rules and protocol logic, and writes alerts and rich protocol logs. It can also sit inline and drop malicious packets. GitHub
- Nmap: the network mapper for inventorying your own network nmap/nmap Nmap is the long-standing open source tool for discovering hosts, open ports, services and operating systems on a network you administer, used to inventory systems and verify that firewall rules behave as intended. GitHub
History
Every saved edit is kept. The plot on the sleeve draws one line per edit. Open any edit to see exactly what changed.
- Dominik +4,135 chars