freeport: Kill Whatever's Holding Your Port
When a dev server won’t start because the port is already in use, you usually have to look up the PID and kill it by hand. This zsh function does that in one command, for a single port or a range:
freeport() {
if [[ $# -ne 1 ]]; then
print -u2 "usage: freeport <port> | <start-end>"
print -u2 " freeport 3000"
print -u2 " freeport 3000-3004"
return 1
fi
local -a ports
local start end
if [[ "$1" == <->-<-> ]]; then
start=${1%%-*}
end=${1##*-}
if (( start > end )); then
print -u2 "freeport: invalid range '$1' (start > end)"
return 1
fi
ports=({$start..$end})
elif [[ "$1" == <-> ]]; then
ports=($1)
else
print -u2 "freeport: invalid port '$1'"
return 1
fi
local port
local -a pids
local -a killed
for port in "${ports[@]}"; do
pids=("${(@f)$(lsof -ti ":$port")}")
pids=("${pids[@]:#}")
if (( ${#pids[@]} == 0 )); then
print "No process found on port $port"
continue
fi
kill "${pids[@]}" && killed+=($port)
done
(( ${#killed[@]} > 0 )) && print "Freed ports: ${killed[*]}"
}Usage: freeport 3000 or freeport 3000-3004.
zsh’s <-> pattern (a numeric glob) tells a single port from a start-end range, and the range is expanded with {$start..$end}, so freeport 3000-3004 walks every port in between.
lsof -ti :3000 finds the PIDs holding a port; the rest just splits the output into an array and kills them. It sends SIGTERM rather than kill -9, so each process gets a chance to shut down cleanly, and a port with nothing running is reported without stopping the rest. Anything it actually freed is listed at the end.
It needs lsof, which ships with macOS and most Linux distributions.