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,既不易冲突,在合著论文里也好记。字段的顺序不影响结果——排序与成形是样式的职责,不是你的。
@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 | 由出版社出版的书籍 | author 或 editor, title, publisher, year |
@inproceedings | 收入会议论文集的报告 | author, title, booktitle, year |
@incollection | 书中自带标题的一章 | author, title, booktitle, publisher, year |
@phdthesis | 博士学位论文(硕士用 @mastersthesis) | author, title, school, year |
@techreport | 研究机构发布的技术报告 | author, title, institution, year |
@unpublished | 尚未刊行的草稿或私人通信 | author, title, note |
@misc | 无处归类的其他项,如网页 | 无必需字段;howpublished 与 note 承担说明 |
标题里的 TeX 为何变成 tex:用花括号保护大写
plain 与 abbrv 会把论文标题除首字母外全部改成小写。因此写成 title = {A Note on TeX and NASA Systems} 的 @article,输出会变成「A note on tex and nasa systems」。专有名词和缩略语一律被压平。防守办法只有一个:给要保留的部分再套一层花括号。写作 {TeX}、{NASA},这些片段就不受转换影响。要注意的是,这种小写化只作用于论文标题(title),书籍标题和 booktitle 不受影响——所以在 @book 里写 {TeX} 虽无害,却也无用,记住这点能少走弯路。
% 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}。
\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 — 编号确定,正文引用与文献列表终于一致,警告到这一遍才停止。
$ 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 ... undefined 和 LaTeX Warning: There were undefined references.,正文里的引用变成 [?],参考文献连同标题一起不见了。十有八九,原因只是跑的遍数不够。还没有 .bbl 时,LaTeX 一行文献也不会印——连标题都没有,是因为 thebibliography 环境本身就写在 .bbl 里面。所以先沉住气,把 latex → bibtex → latex → latex 完整跑一遍。若警告仍在,那么 BibTeX 那边一定另有一条自己的消息。
| 消息 | 出现位置 | 原因与处理 |
|---|---|---|
Citation ... undefined | LaTeX | .bbl 尚不存在或已过期。完整跑一遍 latex → bibtex → latex → latex |
There were undefined references. | LaTeX | 仍有未解析的 \cite 或 \ref;再跑一次 latex |
I found no \citation commands | BibTeX | 既没有 \cite 也没有 \nocite;写上引用,或加 \nocite{*} |
I found no \bibstyle command | BibTeX | 文档里漏写了 \bibliographystyle{...} |
I found no database files | BibTeX | 缺少 \bibliography{...},或指定的 .bib 找不到 |
I found no style file | BibTeX | 不存在该名称的 .bst;检查拼写,或放入投稿方提供的 .bst |
Warning--I didn't find a database entry | BibTeX | 你引用的键不在 .bib 里——拼写错误,或忘了添加该条目 |
若问题依旧,那就该怀疑过期的辅助文件了。改了键名、把 .bib 挪到别的目录、换掉样式——这些改动之后,.aux、.bbl、.blg 里可能还留着上一轮的信息。执行 latexmk -C 会把生成物一并清掉,然后从头重建是最快的路。另外要记得引用键区分大小写:在 BibTeX 眼里,Knuth1984 与 knuth1984 是两份不同的文献。
plain、unsrt、alpha、abbrv 的区别
四种标准样式只在三点上有别——排序顺序、标签形态,以及姓名和期刊名缩写到什么程度——收录的字段完全一致。这并非偶然:plain.bst、unsrt.bst、alpha.bst、abbrv.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 都一行都不用改。
为什么没人手写 .bst:makebst 与 custom-bib
.bst 之所以令人却步,是因为它用后缀栈式语言写成。面向样式设计者的官方文档 btxhak.tex(Oren Patashnik,1988 年 2 月 8 日)开篇就直说:文献样式用后缀栈式语言书写,而样式文件是「一个用无名语言写成的程序」。这门语言连名字都没有。它只有十条命令,但所有值都要压栈、出栈,因此仅仅格式化一个 author 字段,就会拖出一长串逆波兰表达式。照着现成的 .bst 改写尚可,从零设计则很不划算。
$ 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 配合使用。当期刊规定与现成样式差那么一点点时,这是最现实的出路。
处理日文文献:pbibtex 与 upbibtex
原始的 bibtex 以西文为前提,因此含有日文作者名或书名的 .bib 会在排序与字符串处理两方面同时出问题。TeX Live 为此提供了 pbibtex(用于 pLaTeX,按 EUC-JP 码位排序)与 upbibtex(用于 upLaTeX,按 Unicode 码位排序)。关键在于它们不只是换了编码:样式语言本身也被扩展了。新增内置函数 is.kanji.str$ 用于判断字符串是否含非 ASCII 字符;substring$ 经过修改,绝不会把多字节字符从中截断;add.period$ 也被教会了不在「。」「?」这类日文标点之后再补一个句点。其血统上溯至松井正一的 JBibTeX,发行包至今仍把那段历史随文档一并附上。
$ 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样式也有日文对应版本:对应 plain 的 jplain、对应 unsrt 的 junsrt、对应 alpha 的 jalpha、对应 abbrv 的 jabbrv,以及把姓置于开头的 jname。面向学会的则有 jipsj(情报处理学会)、tipsj、tieice(电子情报通信学会)与 jorsj——而这些同样是用 C 预处理器从 jbtxbst.doc 这一份模板切出来的,与西文侧的做法一模一样。构建流程只是换了名字:latex 换成 platex 或 uplatex,bibtex 换成 pbibtex 或 upbibtex。由于要经过 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 文件本身在两者之间是通用的,因此迁移成本比想象中低。四十年前那个把「文献是什么」与「如何印出来」分开的决定,正是在这里回报最大。