A tiny shell utility to quickly kill processes bound to a TCP or UDP port on macOS.
Installs a global killport
command in ~/.local/bin
and adds it to your PATH.
bash -c 'set -euo pipefail; TD="$HOME/.local/bin"; mkdir -p "$TD"; cat > "$TD/killport" <<"EOF"
#!/usr/bin/env bash
set -euo pipefail
show_usage(){ echo "Usage: killport <port> [--udp] [--signal SIG] [--dry-run]"; }
[[ $# -lt 1 ]] && { show_usage; exit 1; }
PORT="$1"; shift || true; PROTO="tcp"; SIGNAL="-9"; DRY_RUN="0"
while [[ $# -gt 0 ]]; do case "$1" in
--udp) PROTO="udp"; shift ;;
--signal|-s) SIGNAL="${2:-}"; [[ -z "${SIGNAL}" ]] && { echo "Missing value for --signal" >&2; exit 1; }; shift 2 ;;
--dry-run|--list) DRY_RUN="1"; shift ;;
-h|--help) show_usage; exit 0 ;;
*) echo "Unknown option: $1" >&2; show_usage; exit 1 ;;
esac; done
command -v lsof >/dev/null 2>&1 || command -v netstat >/dev/null 2>&1 || { echo "Requires lsof or netstat." >&2; exit 1; }
PIDS=""; if command -v lsof >/dev/null 2>&1; then F=""; [[ "$PROTO" == "tcp" ]] && F="-sTCP:LISTEN"; PIDS="$(lsof -nP -i ${PROTO}:"$PORT" ${F} -t 2>/dev/null || true)"; fi
if [[ -z "${PIDS// /}" ]] && command -v netstat >/dev/null 2>&1; then
if [[ "$PROTO" == "tcp" ]]; then PIDS="$(netstat -vanp tcp 2>/dev/null | awk -v port=".$PORT" '\''$4 ~ port"$" {print $9}'\'' | sort -u || true)";
else PIDS="$(netstat -vanp udp 2>/dev/null | awk -v port=".$PORT" '\''$4 ~ port"$" {print $9}'\'' | sort -u || true)"; fi
fi
[[ -z "${PIDS// /}" ]] && { echo "No processes found on ${PROTO} port ${PORT}."; exit 0; }
[[ "$DRY_RUN" == "1" ]] && { echo "Would kill on ${PROTO}:${PORT} (signal ${SIGNAL}): ${PIDS}"; exit 0; }
echo "Killing on ${PROTO}:${PORT} with signal ${SIGNAL}: ${PIDS}"; for pid in $PIDS; do
if kill "${SIGNAL}" "$pid" 2>/dev/null; then echo "Killed PID ${pid}"; else echo "Failed to kill PID ${pid} (may need sudo)"; fi
done
EOF
chmod +x "$TD/killport"
PROFILE="$HOME/.zshrc"; LINE='\n# Add local bin to PATH for killport\nexport PATH="$HOME/.local/bin:$PATH"\n'
grep -qsE "^\s*export PATH=.*\$HOME/.local/bin" "$PROFILE" || { printf "$LINE" >> "$PROFILE"; echo "Added ~/.local/bin to PATH in $PROFILE"; }
echo "Installed killport at $TD/killport. Restart terminal or: source \"$PROFILE\""
'
After install, reload your shell:
source ~/.zshrc
killport <port> [--udp] [--signal SIG] [--dry-run]
killport 3000
— kill whatever is listening on TCP port 3000 with SIGKILL (-9)killport 3000 --signal -15
— graceful terminate (SIGTERM) on port 3000killport 5353 --udp
— target UDP instead of TCPkillport 3000 --dry-run
— show what would be killed
--udp
: Switch protocol from TCP (default) to UDP.--signal
or-s
: Send a specific signal (e.g.,-15
for SIGTERM,-9
for SIGKILL).--dry-run
: Print matching PIDs without killing them.-h
,--help
: Show usage.
- Uses
lsof
when available (preferred), falls back tonetstat
. - Filters to TCP LISTEN sockets by default for TCP.
- Kills all matching PIDs on the chosen port.
- macOS (zsh)
lsof
ornetstat
available on PATH (both are included on macOS)
rm -f ~/.local/bin/killport
sed -i '' '/Add local bin to PATH for killport/d' ~/.zshrc
sed -i '' '/export PATH="\$HOME\/\.local\/bin:\$PATH"/d' ~/.zshrc
- You may need
sudo
if the target process is owned by another user:
sudo killport 3000
- If nothing is found, the command exits successfully and prints a message.
MIT