BibTeX

BibTeX 的版本号至今仍是 0.99d。TeX Live 2024 附带的就是这个号码,而官方文档 btxdoc.tex 依旧署着 1988 年 2 月 8 日的日期,依旧写着「等 BibTeX 1.00 发布后再扩充本文」。1.00 至今未曾发布。即便如此,BibTeX 仍是在 LaTeX 中处理参考文献的基准。原因很简单:它从一开始就把文献是什么.bib 数据库)与文献如何印出来.bst 样式)分开了。本页依次讲解 .bib 的写法,\cite\bibliographystyle\bibliography 各自的职责,latex → bibtex → latex → latex 这四次构建,以及 LaTeX Warning: Citation ... undefined 迟迟不消失时的原因。

BibTeX 为什么是独立于 LaTeX 的程序

BibTeX 不是 LaTeX 的一部分,而是一个独立的可执行程序。更关键的是,它从不读取你的 .tex 文件。它只读 LaTeX 生成的 .aux,从中取出三样东西——引用了哪些键、指定了哪种样式、要打开哪个 .bib——然后把结果写回 .bbl。这种彻底的分工,正是后面那四次构建的根源。标准样式文件开头至今保留着版权行「Copyright (C) 1984, 1985, 1988 Howard Trickey and Oren Patashnik」——那正是 LaTeX 自身尚在成形的年代。BibTeX 不是事后加挂的扩展,而是被设计成几乎同龄的搭档。

这个机制分为三个部件:保存原始文献数据的 .bib 文件;正文中的 \cite 调用与两个命令(\bibliographystyle\bibliography);以及决定外观的 .bst 文件。用 thebibliography 环境在文末手工排列文献,对小文档仍然够用;但一旦同一批文献要在多篇论文之间反复使用,你很快就分不清哪一版才是对的。BibTeX 解决的正是这个问题:数据集中放一处,换投稿目标时只需替换一个样式名,而不是耗掉一个下午。贯穿整个 LaTeX 的「结构与外观分离」思想,在参考文献上被原样套用了一遍。

.bib 条目怎么写:条目类型、引用键、字段

.bib 文件就是列出若干条目的纯文本。每个条目先声明条目类型,例如 @article,然后在花括号里先写引用键,其后是字段,写作 fieldname = {value} 并以逗号分隔。引用键是必须与文档中 \cite{...} 逐字相同的标识符,命名由你决定。惯例是「作者姓+年份」,如 knuth1984,既不易冲突,在合著论文里也好记。字段的顺序不影响结果——排序与成形是样式的职责,不是你的。

references.bib
@string{bstj = "Bell System Technical Journal"}

@book{knuth1984,
  author    = {Donald E. Knuth},
  title     = {The {TeX}book},
  publisher = {Addison-Wesley},
  year      = {1984}
}

@article{shannon1948,
  author  = {Claude E. Shannon},
  title   = {A Mathematical Theory of Communication},
  journal = bstj,          % @string abbreviation, no braces
  volume  = {27},
  number  = {3},
  pages   = {379--423},
  year    = {1948}
}

@inproceedings{lamport1987,
  author    = {Leslie Lamport},
  title     = {Document Production: Visual or Logical?},
  booktitle = {Proceedings of TUG},
  year      = {1987},
  pages     = {19--24}
}

决定哪些字段是必需的,不是 BibTeX 本体,而是样式。用标准的 plain 时,缺失的字段会被逐一点名:Warning--empty journal in shannon1948。这些是警告而非错误,处理不会中断——只是那条信息悄悄从输出里消失,所以务必把警告读完。用 @string{bstj = "..."} 定义缩写后,就能以不带花括号的裸名引用该值。此外 crossref 字段可以让论文集中的某一篇继承父级 @proceedings 条目,会议名和出版社不必对每篇重复书写。

条目类型适用对象plain 的必需字段
@article刊登在期刊上的论文author, title, journal, year
@book由出版社出版的书籍authoreditor, title, publisher, year
@inproceedings收入会议论文集的报告author, title, booktitle, year
@incollection书中自带标题的一章author, title, booktitle, publisher, year
@phdthesis博士学位论文(硕士用 @mastersthesisauthor, title, school, year
@techreport研究机构发布的技术报告author, title, institution, year
@unpublished尚未刊行的草稿或私人通信author, title, note
@misc无处归类的其他项,如网页无必需字段;howpublishednote 承担说明

标题里的 TeX 为何变成 tex:用花括号保护大写

plainabbrv 会把论文标题除首字母外全部改成小写。因此写成 title = {A Note on TeX and NASA Systems}@article,输出会变成「A note on tex and nasa systems」。专有名词和缩略语一律被压平。防守办法只有一个:给要保留的部分再套一层花括号。写作 {TeX}{NASA},这些片段就不受转换影响。要注意的是,这种小写化只作用于论文标题(title),书籍标题和 booktitle 不受影响——所以在 @book 里写 {TeX} 虽无害,却也无用,记住这点能少走弯路。

references.bib
% unprotected: plain.bst prints "A note on tex and nasa systems"
@article{bad,
  author  = {A. One},
  title   = {A Note on TeX and NASA Systems},
  journal = {J. Test},
  year    = {2000}
}

% protected: prints "A note on {TeX} and {NASA} systems"
@article{good,
  author  = {B. Two},
  title   = {A Note on {TeX} and {NASA} Systems},
  journal = {J. Test},
  year    = {2000}
}

% names: separate with "and"; brace a corporate author whole
@misc{org,
  author = {{World Health Organization}},
  title  = {Annual Report},
  year   = {2024}
}

作者名遵循同样的逻辑。多位作者用 and 分隔author = {A. Smith and B. Jones});逗号被保留用于分开姓与名,因此 author = {Smith, Alice} 表示姓 Smith、名 Alice。列表末尾写 and others,样式会替换为「et al.」。麻烦的是团体作者:除非像 {World Health Organization} 那样把整个名称再包一层花括号,否则 BibTeX 会把它拆成姓和首字母。它把姓名当作语法来解析,所以想让某部分免于解析时,就用花括号让它闭嘴——工具依旧只有这一件。

\bibliographystyle\bibliography 究竟做什么

这两个命令与其说是「打印」,不如说是.aux 里留言\bibliographystyle{plain} 会在其中写入 \bibstyle{plain}\bibliography{references} 写入 \bibdata{references},BibTeX 读到后据此行事。\bibliography 还有第二项职责:在它所在的位置输出参考文献列表,因此通常放在正文末尾、\end{document} 之前。其参数不写扩展名——文件即使叫 references.bib,这里也写 references;要读多个数据库时用逗号分隔,如 \bibliography{books,papers}

document.tex
\documentclass{article}
\begin{document}

TeX was created by Knuth~\cite{knuth1984}, building on
Shannon's information theory~\cite{shannon1948,lamport1987}.

% \nocite{*}            % force every entry of the database into the list
\bibliographystyle{plain}
\bibliography{references}

\end{document}

正文中的 \cite{knuth1984} 直接指向 .bib 里的引用键。只有被引用的文献才会进入列表:躺在 .bib 里却从未被 \cite 的条目会被忽略。若要强制输出整个数据库,加上 \nocite{*}——\nocite 只把某文献登记为「已引用」,不在正文留下任何标记。多个键可以合并在一次调用中,如 \cite{shannon1948,lamport1987}。至于 \cite 本身的变体——用 \cite[p.~42]{knuth1984} 附加页码,或 natbib 的作者-年份形式 \citet\citep——属于引用页面的内容。

latex → bibtex → latex → latex:为什么要跑四次

之所以要跑四次,是因为信息每次只朝一个方向流动。没有 .aux,BibTeX 无从得知你引用了什么;没有 .bbl,LaTeX 无从得知该印什么。而「[1]」「[2]」这些编号只有在参考文献列表真正排好之后才确定,要把这些编号回填到正文的 \cite 标记里,就还得再跑一圈。BibTeX 官方文档 btxdoc.tex 本身就写明了这套流程,还补了一句:在极罕见的情况下,可能需要额外再各跑一次 BibTeX 和 LaTeX。

  • 第 1 次 latex — 处理正文,把被引用的键写成 \citation{...},把样式与数据库写成 \bibstyle{...}\bibdata{...},一并存入 .aux。此时参考文献列表尚不存在。
  • bibtex — 只读 .aux,得知涉及哪些键、哪种样式、哪个 .bib;从数据库取出相应条目,按 .bst 的规则成形,把整个 thebibliography 环境写成 .bbl 文件
  • 第 2 次 latex — 读入 .bbl 并排出参考文献列表。但正文里的 \cite 仍在读旧的 .aux,因此 Citation ... undefined 警告在这一遍并不会消失。
  • 第 3 次 latex — 编号确定,正文引用与文献列表终于一致,警告到这一遍才停止。
terminal
$ pdflatex document.tex   # writes document.aux (\citation, \bibstyle, \bibdata)
$ bibtex   document       # note: job name, not document.tex -> writes .bbl and .blg
$ pdflatex document.tex   # pulls in .bbl; citations still undefined here
$ pdflatex document.tex   # numbers settle; warnings clear

命令拼写上唯一的陷阱是:传给 bibtex 的是作业名(不带扩展名),而不是 .tex。敲 bibtex document.tex 会让它去找 document.tex.aux,然后失败。除了结果之外,BibTeX 还会写一份名为 .blg 的日志;事后想重读警告全文时,就打开它。而实际工作中没人手敲这四条命令:latexmk 会查看 .aux,判断是否需要运行 BibTeX 以及需要几轮,一行 latexmk -pdf document.tex 就是全部。

Citation ... undefined 与参考文献一片空白时

你看到 LaTeX Warning: Citation ... undefinedLaTeX Warning: There were undefined references.,正文里的引用变成 [?],参考文献连同标题一起不见了。十有八九,原因只是跑的遍数不够。还没有 .bbl 时,LaTeX 一行文献也不会印——连标题都没有,是因为 thebibliography 环境本身就写在 .bbl 里面。所以先沉住气,把 latex → bibtex → latex → latex 完整跑一遍。若警告仍在,那么 BibTeX 那边一定另有一条自己的消息。

消息出现位置原因与处理
Citation ... undefinedLaTeX.bbl 尚不存在或已过期。完整跑一遍 latex → bibtex → latex → latex
There were undefined references.LaTeX仍有未解析的 \cite\ref;再跑一次 latex
I found no \citation commandsBibTeX既没有 \cite 也没有 \nocite;写上引用,或加 \nocite{*}
I found no \bibstyle commandBibTeX文档里漏写了 \bibliographystyle{...}
I found no database filesBibTeX缺少 \bibliography{...},或指定的 .bib 找不到
I found no style fileBibTeX不存在该名称的 .bst;检查拼写,或放入投稿方提供的 .bst
Warning--I didn't find a database entryBibTeX你引用的键不在 .bib 里——拼写错误,或忘了添加该条目

若问题依旧,那就该怀疑过期的辅助文件了。改了键名、把 .bib 挪到别的目录、换掉样式——这些改动之后,.aux.bbl.blg 里可能还留着上一轮的信息。执行 latexmk -C 会把生成物一并清掉,然后从头重建是最快的路。另外要记得引用键区分大小写:在 BibTeX 眼里,Knuth1984knuth1984 是两份不同的文献。

plainunsrtalphaabbrv 的区别

四种标准样式只在三点上有别——排序顺序标签形态,以及姓名和期刊名缩写到什么程度——收录的字段完全一致。这并非偶然:plain.bstunsrt.bstalpha.bstabbrv.bst 全部出自同一个文件。一份名为 btxbst.doc 的模板被送进 C 预处理器,分别带上 -DPLAIN-DUNSRT-DALPHA-DABBRV,文件开头就是这么写的。四者之所以看起来略有不同,不过是同一份正文条件编译的结果。

样式排序顺序标签与特点
plain按作者字母顺序连续编号 [1];最稳妥的默认值
unsrt按正文中首次引用的顺序连续编号 [1];格式与 plain 完全相同
alpha按标签排序(实际即作者、年份)[Knu84] 式的字母数字标签;在数学类领域更易读
abbrv按作者字母顺序编号与 plain 相同,但缩写名、月份与期刊名以压缩篇幅

BibTeX 的发行包里还带着另外四种样式,其自身的 README 称之为「准标准」:acm(ACM Transactions 风格)、apalike(APA 式作者-年份,需与 apalike.sty 配合)、ieeetr(IEEE Transactions 风格,按引用顺序编号)、siam(SIAM 风格)。工程领域通常从 ieeetr 起步,计算机科学从 acm,心理学与社会科学若需要作者-年份则从 apalike。除此之外,学会与出版社会按投稿规定发布自己的 .bst,若投稿目标已定,先去找他们的那一份。无论换到哪种样式,.bib 与正文中的 \cite 都一行都不用改。

为什么没人手写 .bstmakebstcustom-bib

.bst 之所以令人却步,是因为它用后缀栈式语言写成。面向样式设计者的官方文档 btxhak.tex(Oren Patashnik,1988 年 2 月 8 日)开篇就直说:文献样式用后缀栈式语言书写,而样式文件是「一个用无名语言写成的程序」。这门语言连名字都没有。它只有十条命令,但所有值都要压栈、出栈,因此仅仅格式化一个 author 字段,就会拖出一长串逆波兰表达式。照着现成的 .bst 改写尚可,从零设计则很不划算。

terminal
$ latex makebst      # answer the questions; choose "merlin" as the master file
                     # -> writes a .dbj batch job
$ latex mystyle.dbj  # runs docstrip -> mystyle.bst

人们真正使用的是 custom-bib 宏包,其入口是 makebst。敲下 latex makebst,一套交互式问答便开始:姓是否放在前面、年份要不要加括号、标题是否用斜体——一路回答下来,另一端就产出一个 .bst。它的作者是 Patrick W. Daly,正是把作者-年份引用带到 LaTeX 一侧的 natbib 的作者;makebst 产出的样式本就设计为可与 natbib 配合使用。当期刊规定与现成样式差那么一点点时,这是最现实的出路。

处理日文文献:pbibtexupbibtex

原始的 bibtex 以西文为前提,因此含有日文作者名或书名的 .bib 会在排序与字符串处理两方面同时出问题。TeX Live 为此提供了 pbibtex(用于 pLaTeX,按 EUC-JP 码位排序)与 upbibtex(用于 upLaTeX,按 Unicode 码位排序)。关键在于它们不只是换了编码:样式语言本身也被扩展了。新增内置函数 is.kanji.str$ 用于判断字符串是否含非 ASCII 字符;substring$ 经过修改,绝不会把多字节字符从中截断;add.period$ 也被教会了不在「。」「?」这类日文标点之后再补一个句点。其血统上溯至松井正一的 JBibTeX,发行包至今仍把那段历史随文档一并附上。

terminal
$ uplatex   document.tex   # 1st pass: writes .aux
$ upbibtex  document       # Japanese-aware: writes .bbl
$ uplatex   document.tex   # pulls in .bbl
$ uplatex   document.tex   # resolves references
$ dvipdfmx  document.dvi   # DVI -> PDF

样式也有日文对应版本:对应 plainjplain、对应 unsrtjunsrt、对应 alphajalpha、对应 abbrvjabbrv,以及把姓置于开头的 jname。面向学会的则有 jipsj(情报处理学会)、tipsjtieice(电子情报通信学会)与 jorsj——而这些同样是用 C 预处理器从 jbtxbst.doc 这一份模板切出来的,与西文侧的做法一模一样。构建流程只是换了名字:latex 换成 platexuplatexbibtex 换成 pbibtexupbibtex。由于要经过 DVI,最后用 dvipdfmx 转换。latexmk 可以在配置文件中指定调用它们,因此日文工作同样能自动化。

继续用 BibTeX,还是转向 biblatex/biber

判断的界线很清楚:投稿方指定了 .bst 就用 BibTeX;格式由自己掌握就用 biblatex/biber。BibTeX 的设计以 8 位编码为前提,因此多语种混排的作者名和重音字符都需要额外处理,排序规则也够不着。想在细节上改变体例,最终还是要动 .bst,也就是上一节那门无名的栈式语言。归根结底,BibTeX 的所有弱点都源于同一件事:一个在 1988 年被冻结的设计。

在那一侧等着的是 biblatex(LaTeX 宏包)与它默认的后端 biber。它们原样接收 Unicode,把排序与体例作为 LaTeX 侧的选项暴露出来,让你一行 .bst 都不必写。命令也随之变化——\cite 让位给 \autocite\printbibliography——构建时调用 biber 而非 bibtex。但 .bib 文件本身在两者之间是通用的,因此迁移成本比想象中低。四十年前那个把「文献是什么」与「如何印出来」分开的决定,正是在这里回报最大。