From fdfb064d0cd363c61ebd2edb70c99a49f50ee9ef Mon Sep 17 00:00:00 2001 From: yuetsh <517252939@qq.com> Date: Tue, 8 Sep 2026 05:26:09 -0600 Subject: [PATCH] =?UTF-8?q?fix(=E5=A4=87=E4=BB=BD):=20=E7=A3=81=E7=9B=98?= =?UTF-8?q?=E4=BD=99=E9=87=8F=E6=A3=80=E6=9F=A5=E5=9C=A8=E8=80=81=20mawk?= =?UTF-8?q?=20=E4=B8=8A=E5=B4=A9=E6=8E=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 服务器上跑 backup-db.sh 报: docker/backup-db.sh: 第 132 行:[: 4.29685e+10: 需要整数表达式 `df -Pk | awk 'NR==2 { print $4 * 1024 }'` 让 awk 做了那个乘法。**mawk 1.3.3** (老 Debian 的 /usr/bin/awk)打印超过 2^31 的整数时会退回 OFMT(%.6g),42968547328 就成了 `4.29685e+10`,丢回 [ ] 比大小当场退出。用 debian:buster-slim 复现出了 一模一样的字符串;mawk 1.3.4(现在的 stable)和 busybox awk 都正常打整数, 我本机是 gawk,所以测不出来。 改成原样取 df 的第 4 列(KB),乘 1024 放到 bash 的 64 位算术里做,谁的 awk 都一样。 另外加一层 digits_or_zero:df 或 psql 返回的东西不是纯数字就当「读不出来」, **跳过余量检查照常备份** —— 余量检查是提醒,不该因为读不到它就不备份了。 (顺带把「磁盘剩 0.0 B」那句误导的输出并进警告里。) clear-sessions.sh 里那句 awk 求和也过了一遍:Redis 键数不可能到 2^31,不受影响。 验证:正常路径照旧;把 free_kb 强行喂成 `4.29685e+10`,现在是一条警告加一次 完整备份,不再退出。 Co-Authored-By: Claude Opus 5 Claude-Session: https://claude.ai/code/session_01KqjE6qPo67fqVDKn6Bx7yd --- docker/backup-db.sh | 32 ++++++++++++++++++++++++-------- 1 file changed, 24 insertions(+), 8 deletions(-) diff --git a/docker/backup-db.sh b/docker/backup-db.sh index 2c7b329..8e65aea 100755 --- a/docker/backup-db.sh +++ b/docker/backup-db.sh @@ -120,20 +120,36 @@ case "$OUT_DIR/" in esac ok "备份目录 $OUT_DIR" +# 拿回来的数要进 [ ] 比大小,不是数字就当「读不出来」,不能让它把整个备份带崩 +digits_or_zero() { + case "$1" in + '' | *[!0-9]*) printf '0\n' ;; + *) printf '%s\n' "$1" ;; + esac +} + # datallowconn 是为了跳过 template0:它不让连,pg_database_size 也算不了 db_bytes=$(docker exec "$CONTAINER" psql -U "$DB_USER" -d postgres -tAc \ "select coalesce(sum(pg_database_size(datname)), 0)::bigint from pg_database where datallowconn" \ 2>/dev/null | tr -d '[:space:]' || true) -[ -n "${db_bytes:-}" ] || db_bytes=0 +db_bytes=$(digits_or_zero "${db_bytes:-}") -free_bytes=$(df -Pk "$OUT_DIR" | awk 'NR == 2 { print $4 * 1024 }') -ok "库 $(human "$db_bytes"),磁盘剩 $(human "$free_bytes")" - -if [ "$db_bytes" -gt 0 ] && [ "$free_bytes" -lt "$db_bytes" ]; then - [ "$FORCE" -eq 1 ] \ - || die "磁盘余量比库还小。压缩后通常小一个数量级,确认够用就加 --force +# df 的第 4 列是 KB。**原样取字段,不让 awk 参与算术** —— Debian 的 /usr/bin/awk 是 +# mawk,超过 2^31 的数会按 OFMT(%.6g)打成 `4.29685e+10`,丢回 [ ] 就是 +# 「需要整数表达式」,脚本当场退出。换算放到 bash 的 64 位算术里做,谁的 awk 都一样。 +free_kb=$(digits_or_zero "$(df -Pk "$OUT_DIR" | awk 'NR == 2 { print $4 }')") +free_bytes=$(( free_kb * 1024 )) +# 余量检查是**提醒**,不是前置条件:读不出来就跳过,不能因为读不到 df 就不备份 +if [ "$free_bytes" -eq 0 ]; then + warn "库 $(human "$db_bytes"),磁盘余量读不出来 —— 跳过余量检查" +else + ok "库 $(human "$db_bytes"),磁盘剩 $(human "$free_bytes")" + if [ "$db_bytes" -gt 0 ] && [ "$free_bytes" -lt "$db_bytes" ]; then + [ "$FORCE" -eq 1 ] \ + || die "磁盘余量比库还小。压缩后通常小一个数量级,确认够用就加 --force —— 备份把生产磁盘写满,比没有备份更糟" - warn "磁盘余量不足,--force 已指定,继续" + warn "磁盘余量不足,--force 已指定,继续" + fi fi # ---------------------------------------------------------------- 导出