From d1287799f75f795d9ac03dd0a9b34d9a7dcb3c1f Mon Sep 17 00:00:00 2001 From: Simon Date: Wed, 30 Sep 2026 19:37:32 +0800 Subject: [PATCH] =?UTF-8?q?fix(dev):=20=E7=AB=AF=E5=8F=A3=E6=8E=A2?= =?UTF-8?q?=E6=B5=8B=E6=94=B9=E4=B8=BA=20lsof=20=E4=BC=98=E5=85=88?= =?UTF-8?q?=EF=BC=8C=E4=BF=AE=E5=A4=8D=20dev.sh=20=E8=AF=AF=E5=88=A4"?= =?UTF-8?q?=E6=9C=AA=E8=BF=90=E8=A1=8C"?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit macOS 上 /usr/local/bin/ss 由 iproute2mac 提供(netstat 包装),输出以 TAB 分隔且 -p 不产出 pid=,导致 listener_pids 恒为空: - port_in_use 永远为假 → start 重复拉起 uvicorn 并报 [Errno 48] Address already in use,最终 die "后端启动超时" - status 误报"未运行",stop 定位不到监听进程 改为 lsof 优先、ss 兜底(保留 Linux 真 iproute2 的 pid= 提取),并用 ([^0-9]|$) 界定端口边界以兼容空格/TAB 两种分隔。显式 if 替代 [[ ]] && ——bash 3.2 在 set -e 下会因中途失败的 && 列表直接退出。 --- scripts/dev.sh | 28 ++++++++++++++++++++-------- 1 file changed, 20 insertions(+), 8 deletions(-) diff --git a/scripts/dev.sh b/scripts/dev.sh index 992e22b..9c7f876 100755 --- a/scripts/dev.sh +++ b/scripts/dev.sh @@ -41,15 +41,27 @@ die() { echo "[dev.sh] 错误: $*" >&2; exit 1; } # ---------- 进程探测 ---------- # 监听指定端口的 pid(无则空) -listener_pids() { # $1 port —— ss 优先(lsof 在部分环境对 socket 不可靠) - if command -v ss >/dev/null 2>&1; then - ss -tlnp 2>/dev/null | awk -v p=":$1 " ' - $0 ~ p && /LISTEN/ { - if (match($0, /pid=[0-9]+/)) print substr($0, RSTART+4, RLENGTH-4) - }' - elif command -v lsof >/dev/null 2>&1; then - lsof -t -iTCP:"$1" -sTCP:LISTEN 2>/dev/null || true +# 取值顺序:lsof → ss。 +# 不能把 ss 放在首位:macOS 上 /usr/local/bin/ss 常由 iproute2mac 提供(netstat 包装), +# 其输出以 TAB 分隔且 -p 不产出 pid=,会让匹配恒为空 → port_in_use 永远为假 → +# start 重复拉起进程并报 [Errno 48] Address already in use,status 也误报"未运行"。 +# 真实 iproute2(Linux)的 ss 仍作为兜底,此时可从 users:(("x",pid=NNN)) 取到 pid。 +listener_pids() { # $1 port + local pids="" + if command -v lsof >/dev/null 2>&1; then + pids="$(lsof -t -iTCP:"$1" -sTCP:LISTEN 2>/dev/null || true)" fi + if [[ -z "$pids" ]] && command -v ss >/dev/null 2>&1; then + # ([^0-9]|$) 界定端口边界:兼容 ss 的空格与 TAB 两种分隔,且避免匹配到更长的端口号 + pids="$(ss -tlnp 2>/dev/null | awk -v p=":$1" ' + $0 ~ (p "([^0-9]|$)") && /LISTEN/ { + if (match($0, /pid=[0-9]+/)) print substr($0, RSTART+4, RLENGTH-4) + }' || true)" + fi + if [[ -n "$pids" ]]; then + printf '%s\n' "$pids" + fi + return 0 } port_in_use() { [[ -n "$(listener_pids "$1")" ]]; }