Skip to content

Instantly share code, notes, and snippets.

@0xSG
Last active August 28, 2025 08:02
Show Gist options
  • Save 0xSG/dfe7506edd61d9f470a73e4984998353 to your computer and use it in GitHub Desktop.
Save 0xSG/dfe7506edd61d9f470a73e4984998353 to your computer and use it in GitHub Desktop.
killport — simple macOS CLI to kill a process by port

killport — macOS CLI to kill a process by port

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.

Quick install (Copy-paste this whole command into your terminal and press Enter)

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

Usage

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 3000
  • killport 5353 --udp — target UDP instead of TCP
  • killport 3000 --dry-run — show what would be killed

Options

  • --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.

How it works

  • Uses lsof when available (preferred), falls back to netstat.
  • Filters to TCP LISTEN sockets by default for TCP.
  • Kills all matching PIDs on the chosen port.

Requirements

  • macOS (zsh)
  • lsof or netstat available on PATH (both are included on macOS)

Uninstall

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

Notes

  • 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.

License

MIT

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment