Files
ouc_latex_template/build.sh
T

140 lines
5.3 KiB
Bash
Raw Normal View History

#!/usr/bin/env bash
2026-11-01 09:29:00 +08:00
# 编译模板
#
# 用法:
# bash build.sh 特殊事项说明表 # 编译该目录下默认主文件
# bash build.sh 试卷 试卷题型示例 # 显式指定主文件(不带 .tex 也行)
# bash build.sh all # 全库所有主文件,逐个编译
# bash build.sh all 2>&1 | tee /tmp/v.log # 想留完整日志
#
# 可用环境变量:
# TEXBIN 默认 xelatex
# SILENT 非空时只打印结论行(给批量脚本用)
#
# ⚠️ 三条务必注意
#
# 1) **PDF 不要提交**。同源码编两次,页面一致但内嵌 CreationDate 不同,
2026-11-01 09:29:00 +08:00
# git 会认为文件变了(全库 16 个 PDF 全变 M)。提交前:
# git checkout -- '*.pdf'
# 或者用 git status 确认只 add 了源码。
#
# 2) **每个模板都要在它自己的目录里编**。.sty 里的 Path=../fonts/ 是相对
# 编译时工作目录解析的,从仓库根调用会找不到字体,报一堆
# "The font ... cannot be found"。本脚本已自动 cd,不用手动。
#
# 3) **两遍编译**。目录、页码、LastPage 跨引用要第二遍才稳定。
# 只编一遍会看到「第 ? 页」或者目录页码错位。
set -u
ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
TEXBIN="${TEXBIN:-xelatex}"
SILENT="${SILENT:-}"
die() { echo "$1" >&2; exit 2; }
# 目录 → 主文件。目录名与主文件名不一致的必须在这里登记。
# 简历/ 下有 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=$?
# 有参考文献库时插入 bibtex(教材/ 等模板需要)。
# ⚠️ 判定依据是目录下存在 **任意 .bib** 且不是 biblatex 自动生成的
# "*-blx.bib"(那是 biblatex 的中间产物,不能当输入跑 bibtex)。
# biblatex 的 bcf 后端用 biber,但本库统一用 bibtex 后端(elegantbook
# 的默认),且仓库里的模板都用 bibtex,故这里只调 bibtex。
# bibtex 失败不中断构建 —— 下一遍 xelatex 会用旧的 .bbl,
# 参考文献可能不全,但正文和版式照常验证。
if ( cd "$ROOT/$dir" && ls *.bib 2>/dev/null | grep -qv -- '-blx\.bib$' ); then
( cd "$ROOT/$dir" && bibtex "$name" ) > "/tmp/oucbibtex.$$.log" 2>&1 || true
# bibtex 之后必须再跑一遍让引用编号落位
( cd "$ROOT/$dir" && $TEXBIN -interaction=nonstopmode "$name.tex" ) > "$log1" 2>&1
fi
# 最后一编:交叉引用稳定后的最终结果,统计以这一遍为准
( 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
}
[ $# -eq 0 ] && die "用法: bash build.sh <目录名|all> [主文件名]"
DIR="$1"; TEX="${2:-}"
#----------------------------------------------------------------------
# 全库模式:直接转给 verify_all.sh(那边有完整的 TARGETS 清单)
#----------------------------------------------------------------------
if [ "$DIR" = "all" ]; then
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
fi
if [ -z "$TEX" ]; then
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
fi
# 允许用户写带 .tex 的
TEX="${TEX%.tex}"
if [ ! -f "$ROOT/$DIR/$TEX.tex" ]; then
echo "找不到 $DIR/$TEX.tex" >&2
exit 2
fi
build_one "$DIR" "$TEX"