一键脚本
bash <(curl -sL gitee.com/meimolihan/cmdbox/raw/master/sh/2panel_status_list.sh)
bash <(curl -sL ../sh/2panel_status_list.sh)
效果预览
补充说明
该脚本用于美化显示 2Panel 服务详细状态,基于 systemctl 与 /proc/<PID>/status 实现,适合快速查看 2Panel 进程的运行状况、内存占用与监听端口。
功能特点
- 彩色输出:字段名与值使用不同颜色高亮,运行异常时红色提示
- 基于 systemctl 自动获取 2Panel 主进程 PID
- 读取
/proc/<PID>/status解析虚拟内存、物理内存、线程数 - 通过 lsof 自动检测进程监听端口
- 运行时长格式化为 小时/分钟/秒 可读格式
- 内存自动换算为 MB 显示
- 服务未运行时会给出明确提示并退出
输出说明
脚本输出包含以下字段:
| 字段 | 说明 |
|---|---|
| 进程 PID | 2panel systemd 服务的主进程 PID |
| 监听端口 | 通过 lsof 检测到的进程监听端口 |
| 运行时长 | 服务自启动以来的运行时长(时/分/秒) |
| 虚拟内存 | VmSize 虚拟内存大小(kB / MB) |
| 物理内存 | VmRSS 物理内存占用(kB / MB) |
| 线程数量 | 进程的线程总数 |
| 数据目录 | 2Panel 默认数据目录 |
注意事项
- 需要 systemd 已注册 2panel 服务,
systemctl show 2panel可查询 - 需要读取
/proc/<PID>/status,普通用户通常可读 - 监听端口依赖 lsof 命令,未安装时该项显示"未找到"
- 数据目录默认为
/var/lib/2panel,实际以安装时配置为准 - 彩色输出需要终端支持 ANSI 转义序列
- 服务未运行时会红色提示"2panel 服务未运行"
- 脚本以 bash 编写,确保运行环境支持 bash
脚本源码
#!/bin/bash
set -uo pipefail
export gl_hui=$'\033[38;5;59m'
export gl_hong=$'\033[38;5;9m'
export gl_lv=$'\033[38;5;10m'
export gl_huang=$'\033[38;5;11m'
export gl_lan=$'\033[38;5;32m'
export gl_bai=$'\033[38;5;15m'
export gl_zi=$'\033[38;5;13m'
export gl_bufan=$'\033[38;5;14m'
export reset=$'\033[0m'
break_end() {
echo -e "${gl_lv}操作完成${reset}"
echo -e "${gl_bai}按任意键继续 ${gl_hong}.${gl_huang}.${gl_lv}.${gl_bai}\c"
read -r -n 1 -s
echo ""
clear
}
# 修改:标签靠左,无前置缩进
kv() {
printf "${gl_lan}%-14s${reset} ${gl_lv}%s${reset}\n" "$1" "$2"
}
section() {
echo -e "${gl_zi}▶ $1${reset}"
}
separator() {
echo -e "${gl_bufan}————————————————————————————————————————————————${reset}"
}
get_pid() {
local pid
pid=$(systemctl show -p MainPID 2panel 2>/dev/null | cut -d= -f2)
if [[ -n "$pid" && -d "/proc/$pid" ]]; then
echo "$pid"
return 0
fi
for p in /proc/[0-9]*/exe; do
local target
target=$(readlink "$p" 2>/dev/null) || continue
if [[ "$(basename "$target")" == "2panel" ]]; then
echo "$(basename "$(dirname "$p")")"
return 0
fi
done
return 1
}
get_listen_port() {
local pid=$1
local inodes=""
for fd in /proc/$pid/fd/*; do
local link
link=$(readlink "$fd" 2>/dev/null) || continue
if [[ "$link" =~ ^socket:\[([0-9]+)\]$ ]]; then
inodes+=" ${BASH_REMATCH[1]}"
fi
done
[[ -z "$inodes" ]] && return
local proto
for proto in tcp tcp6; do
local line
while read -r line; do
[[ -z "$line" ]] && continue
local fields=($line)
[[ ${#fields[@]} -lt 10 ]] && continue
[[ "${fields[3]}" != "0A" ]] && continue
local inode="${fields[9]}"
if [[ " $inodes " == *" $inode "* ]]; then
local hex_port="${fields[1]##*:}"
printf "%d" "0x$hex_port" 2>/dev/null
return
fi
done < <(tail -n +2 /proc/$pid/net/$proto 2>/dev/null)
done
}
proc_field() {
local pid=$1 field=$2
awk -v f="$field" '$1==f":" {print $2}' /proc/$pid/status 2>/dev/null
}
# ── 计算运行时长 ──
get_uptime() {
local pid=$1
local start_ticks uptime_sec elapsed
start_ticks=$(awk '{print $22}' /proc/$pid/stat 2>/dev/null) || return
uptime_sec=$(awk '{printf "%d", $1}' /proc/uptime 2>/dev/null) || return
(( start_ticks <= 0 || uptime_sec <= 0 )) && return
elapsed=$(( uptime_sec - start_ticks / 100 ))
(( elapsed < 0 )) && elapsed=0
printf "%d小时 %d分钟 %d秒" $((elapsed/3600)) $(((elapsed%3600)/60)) $((elapsed%60))
}
fmt_mem() {
local kb=${1:-0}
(( kb == 0 )) && { echo "未知"; return; }
if (( kb >= 1048576 )); then
printf "%d kB (%.2f GB)" "$kb" "$(awk "BEGIN{printf \"%.2f\", $kb/1048576}")"
else
printf "%d kB (%.2f MB)" "$kb" "$(awk "BEGIN{printf \"%.2f\", $kb/1024}")"
fi
}
main() {
local pid
pid=$(get_pid) || {
echo -e "${gl_hong}❌ 2panel 服务未运行${reset}"
break_end
return 1
}
clear
echo -e "${gl_zi}>>> 2Panel 服务状态${reset}"
separator
local vm_size vm_rss threads
vm_size=$(proc_field "$pid" VmSize)
vm_rss=$(proc_field "$pid" VmRSS)
threads=$(proc_field "$pid" Threads)
local port uptime_str nfd
port=$(get_listen_port "$pid")
uptime_str=$(get_uptime "$pid")
nfd=$(ls /proc/$pid/fd 2>/dev/null | wc -l)
section "进程"
kv " 进程 PID" "$pid"
kv " 线程数量" "${threads:-未知}"
kv " 监听端口" "${port:-未找到}"
kv " 运行时长" "${uptime_str:-未知}"
section "内存"
kv " 虚拟内存" "$(fmt_mem "$vm_size")"
kv " 物理内存" "$(fmt_mem "$vm_rss")"
section "资源"
kv " 打开文件" "${nfd:-?}"
separator
kv " 数据目录" "/var/lib/2panel"
kv " 安装路径" "$(readlink /proc/$pid/exe 2>/dev/null || echo '未知')"
separator
break_end
}
main
创建本地脚本
new_script="new_test.sh"
cat > "$new_script" << 'EOF'
#!/bin/bash
# 粘贴脚本源码
EOF
# 保留本地脚本,去掉 rm -f "$new_script"
chmod +x "$new_script" && ./"$new_script" && rm -f "$new_script"