2026-10-29 12:01:06 +08:00
|
|
|
|
#!/usr/bin/env bash
|
2026-10-29 21:50:34 +08:00
|
|
|
|
# 在 WSL 内编译模板(WSL 原生版,无需 ssh/scp)
|
2026-10-29 12:01:06 +08:00
|
|
|
|
#
|
2026-10-29 21:50:34 +08:00
|
|
|
|
# 这套仓库的全部工作都在 WSL 内完成:编辑、编译、查看、提交、提工单。
|
|
|
|
|
|
# Windows 侧只通过 \\wsl$\<发行版>\... 这个 UNC 路径读取文件(只读浏览)。
|
2026-10-29 12:01:06 +08:00
|
|
|
|
#
|
|
|
|
|
|
# 用法:
|
2026-10-29 21:50:34 +08:00
|
|
|
|
# bash build.sh 特殊事项说明表 # 编译该目录下默认主文件
|
|
|
|
|
|
# bash build.sh 试卷 试卷题型示例 # 显式指定主文件(不带 .tex 也行)
|
|
|
|
|
|
# bash build.sh all # 全库所有主文件,逐个编译
|
|
|
|
|
|
# bash build.sh all 2>&1 | tee /tmp/v.log # 想留完整日志
|
2026-10-29 12:01:06 +08:00
|
|
|
|
#
|
2026-10-29 21:50:34 +08:00
|
|
|
|
# 可用环境变量:
|
|
|
|
|
|
# TEXBIN 默认 xelatex
|
|
|
|
|
|
# SILENT 非空时只打印结论行(给批量脚本用)
|
2026-10-29 12:01:06 +08:00
|
|
|
|
#
|
2026-10-29 21:50:34 +08:00
|
|
|
|
# ⚠️ 三条务必注意
|
2026-10-29 12:01:06 +08:00
|
|
|
|
#
|
2026-10-29 21:50:34 +08:00
|
|
|
|
# 1) **PDF 不要提交**。同源码编两次,页面一致但内嵌 CreationDate 不同,
|
|
|
|
|
|
# git 会认为文件变了(全库 13 个 PDF 全变 M)。提交前:
|
|
|
|
|
|
# git checkout -- '*.pdf'
|
|
|
|
|
|
# 或者用 git status 确认只 add 了源码。
|
2026-10-29 12:01:06 +08:00
|
|
|
|
#
|
2026-10-29 21:50:34 +08:00
|
|
|
|
# 2) **每个模板都要在它自己的目录里编**。.sty 里的 Path=../fonts/ 是相对
|
|
|
|
|
|
# 编译时工作目录解析的,从仓库根调用会找不到字体,报一堆
|
|
|
|
|
|
# "The font ... cannot be found"。本脚本已自动 cd,不用手动。
|
|
|
|
|
|
#
|
|
|
|
|
|
# 3) **两遍编译**。目录、页码、LastPage 跨引用要第二遍才稳定。
|
|
|
|
|
|
# 只编一遍会看到「第 ? 页」或者目录页码错位。
|
2026-10-29 12:01:06 +08:00
|
|
|
|
set -u
|
|
|
|
|
|
|
2026-10-29 21:50:34 +08:00
|
|
|
|
ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
2026-10-29 12:01:06 +08:00
|
|
|
|
TEXBIN="${TEXBIN:-xelatex}"
|
2026-10-29 21:50:34 +08:00
|
|
|
|
SILENT="${SILENT:-}"
|
2026-10-29 12:01:06 +08:00
|
|
|
|
|
|
|
|
|
|
die() { echo "$1" >&2; exit 2; }
|
|
|
|
|
|
|
2026-10-29 21:50:34 +08:00
|
|
|
|
# 目录 → 主文件。目录名与主文件名不一致的必须在这里登记。
|
|
|
|
|
|
# 简历/ 下有 fontawesomesymbols-*.tex 等宏包片段,不能拿 ls 第一个 .tex 当主文件。
|
|
|
|
|
|
mainfile_of() {
|
|
|
|
|
|
case "$1" in
|
|
|
|
|
|
幻灯片) echo "slides" ;;
|
|
|
|
|
|
科技报告) echo "report" ;;
|
|
|
|
|
|
简历) echo "简历" ;;
|
|
|
|
|
|
试卷) echo "" ;; # 有两个主文件,必须显式指定
|
|
|
|
|
|
*) echo "$1" ;;
|
|
|
|
|
|
esac
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
# 编一个:$1=目录 $2=主文件名(不带 .tex)
|
|
|
|
|
|
build_one() {
|
|
|
|
|
|
local dir="$1" name="$2"
|
|
|
|
|
|
local log="/tmp/oucbuild.$$.log"
|
|
|
|
|
|
local log1="/tmp/oucbuild.$$.1.log"
|
|
|
|
|
|
|
|
|
|
|
|
# 第一遍:产出 .aux/.toc,允许非致命错误(TOC 还没生成时会警告)
|
|
|
|
|
|
( cd "$ROOT/$dir" && $TEXBIN -interaction=nonstopmode "$name.tex" ) > "$log1" 2>&1
|
|
|
|
|
|
local rc1=$?
|
|
|
|
|
|
# 第二遍:交叉引用稳定后的最终结果,统计以这一遍为准
|
|
|
|
|
|
( cd "$ROOT/$dir" && $TEXBIN -interaction=nonstopmode "$name.tex" ) > "$log" 2>&1
|
|
|
|
|
|
local rc2=$?
|
|
|
|
|
|
|
|
|
|
|
|
local err over under pages
|
|
|
|
|
|
err=$(grep -c '^!' "$log" 2>/dev/null || :)
|
|
|
|
|
|
over=$(grep -c 'Overfull' "$log" 2>/dev/null || :)
|
|
|
|
|
|
under=$(grep -c 'Underfull' "$log" 2>/dev/null || :)
|
|
|
|
|
|
pages=$(grep -o 'Output written on .*' "$log" 2>/dev/null | tail -1)
|
|
|
|
|
|
|
|
|
|
|
|
if [ -z "$SILENT" ]; then
|
|
|
|
|
|
echo "=== $dir / $name ==="
|
|
|
|
|
|
echo " error : $err"
|
|
|
|
|
|
echo " Overfull : $over"
|
|
|
|
|
|
echo " Underfull : $under"
|
|
|
|
|
|
echo " ${pages:-(无输出,见 $log)}"
|
|
|
|
|
|
else
|
|
|
|
|
|
printf '%-24s err=%-2s over=%-2s under=%-2s %s\n' \
|
|
|
|
|
|
"$dir" "$err" "$over" "$under" "$(echo "$pages" | sed 's/Output written on .*(\([0-9]*\) page.*/\1页/')"
|
|
|
|
|
|
fi
|
|
|
|
|
|
|
|
|
|
|
|
if [ "$rc2" -ne 0 ]; then
|
|
|
|
|
|
echo "--- 错误片段($log)---" >&2
|
|
|
|
|
|
grep -A6 '^!' "$log" 2>/dev/null | head -20 | sed 's/^/ /' >&2
|
|
|
|
|
|
# 保留失败日志,方便排查;成功时删掉
|
|
|
|
|
|
return "$rc2"
|
|
|
|
|
|
fi
|
|
|
|
|
|
rm -f "$log" "$log1"
|
|
|
|
|
|
return 0
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-10-29 12:01:06 +08:00
|
|
|
|
[ $# -eq 0 ] && die "用法: bash build.sh <目录名|all> [主文件名]"
|
2026-10-29 21:50:34 +08:00
|
|
|
|
|
2026-10-29 12:01:06 +08:00
|
|
|
|
DIR="$1"; TEX="${2:-}"
|
|
|
|
|
|
|
2026-10-29 21:50:34 +08:00
|
|
|
|
#----------------------------------------------------------------------
|
|
|
|
|
|
# 全库模式:直接转给 verify_all.sh(那边有完整的 TARGETS 清单)
|
|
|
|
|
|
#----------------------------------------------------------------------
|
2026-10-29 12:01:06 +08:00
|
|
|
|
if [ "$DIR" = "all" ]; then
|
2026-10-29 21:50:34 +08:00
|
|
|
|
exec bash "$ROOT/verify_all.sh"
|
|
|
|
|
|
fi
|
|
|
|
|
|
|
|
|
|
|
|
#----------------------------------------------------------------------
|
|
|
|
|
|
# 单目录模式
|
|
|
|
|
|
#----------------------------------------------------------------------
|
|
|
|
|
|
if [ ! -d "$ROOT/$DIR" ]; then
|
|
|
|
|
|
echo "没有这个目录:$DIR" >&2
|
|
|
|
|
|
echo "可选:" >&2
|
|
|
|
|
|
( cd "$ROOT" && ls -d */ 2>/dev/null | sed 's|/$||' | sed 's/^/ /' ) >&2
|
|
|
|
|
|
exit 2
|
2026-10-29 12:01:06 +08:00
|
|
|
|
fi
|
|
|
|
|
|
|
|
|
|
|
|
if [ -z "$TEX" ]; then
|
2026-10-29 21:50:34 +08:00
|
|
|
|
TEX="$(mainfile_of "$DIR")"
|
|
|
|
|
|
if [ -z "$TEX" ]; then
|
|
|
|
|
|
echo "$DIR/ 有多个主文件,请显式指定:" >&2
|
|
|
|
|
|
( cd "$ROOT/$DIR" && ls *.tex 2>/dev/null | grep -v fontawesome | sed 's/\.tex$//' | sed 's/^/ /' ) >&2
|
|
|
|
|
|
echo "例: bash build.sh $DIR $(cd "$ROOT/$DIR" && ls *.tex 2>/dev/null | grep -v fontawesome | head -1 | sed 's/\.tex$//')" >&2
|
|
|
|
|
|
exit 2
|
|
|
|
|
|
fi
|
2026-10-29 12:01:06 +08:00
|
|
|
|
fi
|
|
|
|
|
|
|
2026-10-29 21:50:34 +08:00
|
|
|
|
# 允许用户写带 .tex 的
|
|
|
|
|
|
TEX="${TEX%.tex}"
|
2026-10-29 12:01:06 +08:00
|
|
|
|
|
2026-10-29 21:50:34 +08:00
|
|
|
|
if [ ! -f "$ROOT/$DIR/$TEX.tex" ]; then
|
|
|
|
|
|
echo "找不到 $DIR/$TEX.tex" >&2
|
|
|
|
|
|
exit 2
|
2026-10-29 12:01:06 +08:00
|
|
|
|
fi
|
|
|
|
|
|
|
2026-10-29 21:50:34 +08:00
|
|
|
|
build_one "$DIR" "$TEX"
|