Commit 637b5147 authored by Data Governance Dev's avatar Data Governance Dev

chore(skills): 新增 kill-port skill — 跨平台杀端口进程

- SKILL.md
  - 项目级 skill(.claude/skills/kill-port/)
  - 默认杀 8765 (web) / 8766 (web2) / 5173 / 5174 (Vite dev)
  - 可传自定义端口
  - 退出码 0/1/2 分别表示成功/端口空闲/杀失败
- scripts/kill-port.sh(Git Bash / Linux / macOS)
  - 自动检测平台:netstat.exe+taskkill.exe (Windows) / lsof+kill -9 (POSIX)
  - 多端口串行处理,独立退出码
  - 杀完二次确认端口已释放
- scripts/kill-port.bat(Windows cmd 原生版)
  - 同等功能,:kill_one 子函数处理单端口
parent 91d91703
---
name: kill-port
description: 杀掉占用指定 TCP 端口的进程(跨平台:Windows Git Bash / Windows cmd / Linux / macOS)。默认杀掉本项目常用的 web (8765) / web2 (8766) / 前端 dev (5173/5174) 四个端口。
metadata:
argument-hint: "[port ...]"
allowed-tools: Bash
---
# kill-port —— 杀掉占用端口的进程
## 何时使用
- 用户说「杀掉 8766」「杀进程」「端口被占」「释放端口」「kill the process on port xxx」
- 启动后端/前端时端口已被占用
- 重启 web / web2 前后端调试服务
**自动默认端口**(用户不传任何参数时):8765 8766 5173 5174
(分别对应 web / web2 的 FastAPI 后端 + Vite 前端 dev server)
## 调用方式
通过 Bash 工具执行本目录下的脚本:
```bash
# Windows + Git Bash
bash .claude/skills/kill-port/scripts/kill-port.sh
# 自定义端口
bash .claude/skills/kill-port/scripts/kill-port.sh 9000
# 多个端口
bash .claude/skills/kill-port/scripts/kill-port.sh 8765 8766
# Windows cmd / PowerShell
.claude\skills\kill-port\scripts\kill-port.bat
.claude\skills\kill-port\scripts\kill-port.bat 9000
```
## 退出码
| 码 | 含义 |
|---|---|
| 0 | 端口释放 / 已杀掉占用进程 |
| 1 | 端口已空闲(无需处理)|
| 2 | 杀进程失败(脚本内部错误)|
## 实现说明
- Windows: `netstat.exe -ano` + `taskkill.exe /F /PID`
- Linux / macOS: `lsof -ti tcp:<PORT>` + `kill -9`
- 自动检测平台,无需用户指定
- 二次确认端口已释放(避免假杀)
- 多端口串行处理,每个端口独立报告成功/失败
## 不要做的事
- ❌ 不要在杀进程前征求用户确认 —— 端口被占调试场景下用户已经明确要释放
- ❌ 不要杀掉非指定端口的进程(避免误杀系统服务)
- ❌ 不要在脚本里加 `sudo` / `runas`(web 项目是开发环境,端口冲突用强杀即可)
\ No newline at end of file
@echo off
REM ── 杀掉占用 TCP 端口的进程(Windows 原生 cmd 版)──
REM
REM 用法:
REM kill-port.bat REM 杀默认端口 8765 8766 5173 5174
REM kill-port.bat 9000 REM 杀指定端口
REM kill-port.bat 8765 9000 3000 REM 杀多个端口
REM
REM 退出码(最后处理的端口):
REM 0 杀掉占用进程成功
REM 1 端口已空闲(无需处理)
REM 2 杀进程失败
setlocal enabledelayedexpansion
REM 默认端口:web (8765) / web2 (8766) / 前端 dev (5173/5174)
set "DEFAULT_PORTS=8765 8766 5173 5174"
REM 收集端口
set "PORTS="
:parse_args
if "%~1"=="" goto :have_ports
if defined PORTS (
set "PORTS=!PORTS! %~1"
) else (
set "PORTS=%~1"
)
shift
goto :parse_args
:have_ports
if "%PORTS%"=="" set "PORTS=%DEFAULT_PORTS%"
echo [kill-port] 目标端口: %PORTS%
REM ── 主循环:逐个端口处理 ──
set "LAST_RC=0"
for %%P in (%PORTS%) do (
call :kill_one %%P
set "LAST_RC=!errorlevel!"
)
REM 用一个空 for 把 errorlevel 透传(cmd 的怪特性)
exit /b %LAST_RC%
REM ─────────────────────────────────────────────
REM 单端口处理函数
REM ─────────────────────────────────────────────
:kill_one
setlocal
set "PORT=%~1"
REM 找 PID
set "PIDS="
for /f "tokens=5" %%X in ('netstat -ano ^| findstr ":%PORT% " ^| findstr "LISTENING"') do (
if not defined PIDS (
set "PIDS=%%X"
) else (
set "PIDS=!PIDS! %%X"
)
)
if "%PIDS%"=="" (
echo [kill-port] 端口 %PORT% 已空闲
endlocal & exit /b 1
)
echo [kill-port] 端口 %PORT% 占用 PID: %PIDS%
REM 强杀
set "KILL_OK=0"
for %%X in (%PIDS%) do (
echo [kill-port] -^> 杀 PID %%X
taskkill /F /PID %%X 1>nul 2>nul
if !errorlevel! equ 0 set /a KILL_OK+=1
)
REM 二次确认
timeout /t 1 /nobreak > nul 2>&1
set "REMAINING="
for /f "tokens=5" %%X in ('netstat -ano ^| findstr ":%PORT% " ^| findstr "LISTENING"') do (
set "REMAINING=%%X"
goto :check_remain
)
:check_remain
if "%REMAINING%"=="" (
echo [kill-port] ✅ 端口 %PORT% 已释放(杀掉 %KILL_OK% 个进程)
endlocal & exit /b 0
) else (
echo [kill-port] ❌ 端口 %PORT% 仍有进程占用: %REMAINING% 1>&2
endlocal & exit /b 2
)
\ No newline at end of file
#!/usr/bin/env bash
# ── 杀掉占用 TCP 端口的进程(跨平台版) ──
#
# 用法:
# bash kill-port.sh # 杀默认端口(8765 8766 5173 5174)
# bash kill-port.sh 9000 # 杀指定端口
# bash kill-port.sh 8765 9000 3000 # 杀多个端口
#
# 平台:
# - Windows Git Bash / WSL: netstat.exe + taskkill.exe
# - Linux / macOS: lsof + kill -9
#
# 退出码(每个端口):
# 0 端口释放成功 / 已杀掉进程
# 1 端口空闲(无需处理)
# 2 杀进程失败
#
# 整个脚本的总退出码 = 最后一个端口的退出码。
set -u
# 默认端口:本项目常用 web (8765) / web2 (8766) / 前端 dev (5173/5174)
DEFAULT_PORTS=(8765 8766 5173 5174)
if [ "$#" -eq 0 ]; then
PORTS=("${DEFAULT_PORTS[@]}")
else
PORTS=("$@")
fi
echo "[kill-port] 目标端口: ${PORTS[*]}"
# ── 平台检测 ──
if command -v netstat.exe > /dev/null 2>&1; then
PLATFORM="windows"
elif command -v lsof > /dev/null 2>&1; then
PLATFORM="posix"
else
echo "[kill-port] 找不到 netstat.exe 或 lsof,无法定位 PID" >&2
exit 2
fi
echo "[kill-port] 平台: $PLATFORM"
# ── 单端口处理函数 ──
kill_one() {
local PORT="$1"
# 找 PID
local PIDS=""
if [ "$PLATFORM" = "windows" ]; then
# netstat.exe -ano 列所有 TCP;过滤 ":$PORT " + LISTENING
PIDS=$(netstat.exe -ano 2>/dev/null \
| grep ":$PORT " \
| grep "LISTENING" \
| awk '{print $NF}' \
| sort -u)
else
# POSIX
PIDS=$(lsof -ti tcp:"$PORT" 2>/dev/null | sort -u)
fi
if [ -z "${PIDS:-}" ]; then
echo "[kill-port] 端口 $PORT 已空闲"
return 1
fi
echo "[kill-port] 端口 $PORT 占用 PID: $(echo "$PIDS" | tr '\n' ' ')"
# 杀
local KILL_OK=0
for PID in $PIDS; do
echo "[kill-port] → 杀 PID $PID"
if [ "$PLATFORM" = "windows" ]; then
taskkill.exe //F //PID "$PID" 2>&1 | sed 's/^/ /'
local RC=${PIPESTATUS[0]}
else
# POSIX:先 SIGTERM 再 SIGKILL
kill "$PID" 2>/dev/null && sleep 1
kill -9 "$PID" 2>/dev/null
local RC=$?
fi
if [ "$RC" -eq 0 ]; then
KILL_OK=$((KILL_OK + 1))
else
echo "[kill-port] PID $PID 杀失败(退出码 $RC)" >&2
fi
done
# 二次确认
sleep 1
local REMAINING=""
if [ "$PLATFORM" = "windows" ]; then
REMAINING=$(netstat.exe -ano 2>/dev/null \
| grep ":$PORT " \
| grep "LISTENING" \
| awk '{print $NF}' \
| sort -u)
else
REMAINING=$(lsof -ti tcp:"$PORT" 2>/dev/null | sort -u)
fi
if [ -z "${REMAINING:-}" ]; then
echo "[kill-port] ✅ 端口 $PORT 已释放(杀掉 $KILL_OK 个进程)"
return 0
else
echo "[kill-port] ❌ 端口 $PORT 仍有进程占用: $REMAINING" >&2
return 2
fi
}
# ── 主循环:逐个端口处理 ──
LAST_RC=0
for P in "${PORTS[@]}"; do
kill_one "$P"
LAST_RC=$?
done
exit "$LAST_RC"
\ No newline at end of file
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment