# bibupdate

[![Version](https://img.shields.io/badge/version-2.1.0-success)](https://github.com/AndrewMathas/BibUpdate)
[![CTAN](https://img.shields.io/ctan/v/bibupdate?color=blue)](https://ctan.org/pkg/bibupdate)[![Requires Python 3.9+](https://img.shields.io/badge/requires-python3.9%2B-important)](https://www.python.org/)
[![GPLv3](https://img.shields.io/badge/license-GPLv3-blueviolet.svg)](https://www.gnu.org/licenses/gpl-3.0.en.html)

Automatically update bibtex files

Usage:

    bibupdate [-h|-H] [-a] [-x] [-c] [-k] [-i FIELDS] [-l LOG]
              [-m | -M | -n] [-o] [-q] [--threads N] [-w LEN]
              [--deduplicate] [--remove-duplicate-papers] [--rename-duplicate-keys]
              [--list-duplicates] [--list-papers] [--list-keys]
              [-t FILE.tex [FILE.tex ...]]
              [--output FILE.bib] bibtexfile [outputfile]
    bibupdate --merge [options] FILE.bib FILE.bib [FILE.bib ...]

This is a command line tool for updating the entries in a [BibTeX] file using the
tools provided by the American Mathematical Society: [mrlookup], [MathSciNet]
and [MRef]. By default [bibupdate] uses [mrlookup] to update `article`, `book`,
`inproceedings` and `incollection` entries when they do not have an
`mrnumber` field. Entries are not updated if they already have an
`mrnumber` field, even an empty one, unless `--all` or `--check`
is used. The `-x` option makes [bibupdate] look for each paper in the
[arXiv] and add `eprint` and `archiveprefix` fields for all the papers
that it finds. In addition, [bibupdate] is able to merge bibliography
files, removing duplicate papers and keys in the process and,
optionally, updating citations to renamed duplicate keys in [LaTeX] files.

By default, [bibupdate] does not change your original file. Instead, it
writes the updated entries to a new file, with the filename given by 
adding an `updated_` prefix, so *file.bib* becomes *updated_file.bib*.
To update the bib file in place, use `--overwrite`, or give a output
filename. Existing output files are backed up with `.bak` extensions,
but `--overwrite` should still be used with care.

This should be used with care because you
can potentially lose data.

**Options by task**:

**Updating and checking**

    -m, --mrlookup        use mrlookup to update bibtex entries (default)
    -M, --mathscinet      use mathscinet to update bibtex entries (less flexible)
    -n, --mref            use mref to update bibtex entries
    -a, --all             update or validate ALL BibTeX entries
    -x, --arxiv           add arXiv eprint fields to entries
    -c, --check           check all entries and report duplicates without writing a file

**Duplicate listing**

    --list-duplicates     list duplicate papers and keys without writing a file
    --list-papers         list duplicate papers only
    --list-keys           list repeated citation keys only

**Duplicate cleanup**

    --deduplicate         remove duplicate papers and rename repeated keys
    --remove-duplicate-papers
                          remove duplicate papers, keeping the first
    --rename-duplicate-keys
                          rename repeated keys using authors and year
    --merge               merge two or more .bib files and clean up duplicates
    -t, --texfile FILE.tex [FILE.tex ...]
                          update citations in listed TeX files during cleanup

**Output and formatting**

    --output FILE.bib     write the bibliography to this file
    -o, --overwrite       update/overwrite the bibtex file (use with care)
    -i FIELDS, --ignored-fields FIELDS
                          space-separated list of bibtex fields to ignore
    -k, --keep-fonts      do NOT replace fonts \Bbb, \germ and \scr in titles
    -w LEN, --wrap LEN    wrap bibtex fields to specified width
    --threads N           number of concurrent AMS lookups (default: 1)

**Reports and logging**

    -q, --quiet           brief updates and missed lookups
    -qq                   only print errors
    -l LOG, --log LOG     log messages to specified file (defaults to stdout)

**Help and version**

    -h, --help            show grouped options and exit
    -H, --Help            print full program description

**Note:**
As described below, you should check the updated `.bib` file for errors
before deleting the original [BibTeX] file.

[BibTeX] is widely used by the [LaTeX] community to maintain publication databases.
This script attempts to add missing fields to the papers in a [BibTeX] database
file by querying [mrlookup] and getting the missing publication data from there.
This is not completely routine because an [mrlookup] search requires either the
names of the authors, or the title of the article, and both of these can have
non-standard representations. If the article is already published, then it is
also possible to use the publication year and its page numbers as part
of the search. To search on [mrlookup] we:

- use the first author's surname (accents and compound surnames can be problematic)
- use numeric page ranges, or a single numeric page, when available
- include the year for books, or when a numeric first page is available
- use the cleaned title when a numeric first page is not available

The author query uses only the first author's surname because [mrlookup] does not
accept multiple author names joined by 'and'. Braces used to protect capitals in
titles (for example `{Kac-Moody}`) are removed when searching and
matching, with the title stored in the [BibTeX] file retaining its braces.

If there is a unique match from [mrlookup], then [bibupdate] updates the entry in
the [BibTeX] file using the field values returned by an [mrlookup] search, except for
the citation key and any fields excluded by `--ignored-fields`. Any fields that are
not returned by [mrlookup], such as `eprint`, are retained. By default, a message is
printed whenever an entry in the database is changed. If the title of the retrieved paper
does not (fuzzily) match that of the original article, then the entry is NOT
updated and a warning message is printed.

Although some care is taken to ensure that the new [BibTeX] entries correspond
to the original entry in the [BibTeX] file, there is always a (small?)
chance the new entry corresponds to a completely different paper. In my
experience this happens rarely, and mostly with unpublished manuscripts. In any
case, before you delete your original [BibTeX] file *you are strongly advised to
check the updated BibTeX file carefully for errors!*

By default, the program prints a compact listing of any updated paper in the
[BibTeX] file, including any added [arXiv] fields. This can generate a
lot of output the first time [bibupdate] is run on large files, later runs
produce much less output.

As [bibupdate] calls [mrlookup], this program will only be useful if you have
papers in your database that are listed in [MathSciNet]. As described below it is
also possible to call [MathSciNet] directly, however, this is less flexible
because the `mrnumber` field for each paper is required.

I wrote this script because I wanted to automatically update the papers
in my [BibTeX] files when they were published, so that the file has
up-to-date information on all of the papers in the file, including
journal names, [arXiv] links, and DOIs for each paper. As a bonus
the script helped me to correct many minor errors that had crept
into my [BibTeX] file over the years (for example, incorrect page
numbers and publication years).

## Options and defaults

By default, [bibupdate] uses [mrlookup], sending one AMS lookup request at
a time. It prints a compact listing for each entry in the file that is
updated, writing the updated [BibTeX] file to `updated_file.bib` if the
original input file was `file.bib`.

### Updating and checking

#### `-m, --mrlookup`

Use [mrlookup] to update [BibTeX] entries (default)

#### `-M, --mathscinet`

Use [MathSciNet] to update [BibTeX] entries

#### `-n, --mref`

Use [MRef] to update [BibTeX] entries

By default [mrlookup] is used. Its main advantage is that it has a more
flexible search mechanism using author, title, year and page numbers,
so it can find papers even when they do not yet have an `mrnumber`.

With `-M`, the entry is looked up using its `mrnumber`. Entries with missing,
empty or non-numeric MR numbers are skipped, including with `--all` and `--check`.

With `-n`, the full [BibTeX] entry is handed to [MRef] as a free-form
reference. The best matching record is then checked against the original
title. Like [mrlookup], [MRef] normally checks only `article`, `book`,
`inproceedings` and `incollection` entries without an `mrnumber` field.
Use `--all` to check all recognised entry types.

#### `-a, --all`

Update or validate ALL BibTeX entries

#### `-x, --arxiv`

Update the arXiv entry for each paper

When the paper is found, add `eprint` and `archiveprefix` fields to
the [BibTeX] entry:

    eprint = {2211.07069},
    archiveprefix = {arXiv}

[bibupdate] searches the [arXiv] using the significant words in the
title. A paper returned by the [arXiv] is counted as a match only
when there is a unique paper with a sufficiently good (fuzzy) match.
The `-x` option can be combined with any of the `-m`, `-M` or
`-n` lookup tools. Entries with an existing `eprint` field, even an
empty one, are skipped unless `-a` or `--check` is used. Entries
without a usable title cannot be searched.

As requested by the [arXiv], [bibupdate] waits at least 3
seconds after each completed [arXiv] request before sending the next one.
Updating a large database with `-x` can take a long time.

#### `-c, --check`

Check all entries and report duplicates, printing compact listings for each
database entry that would be changed. No output file is written. This option
implies `--all`.

#### `--threads N`

Number of concurrent AMS lookups

Use `--threads N` to run `N` searches in parallel. [arXiv] lookups remain
sequential and keep their delay between requests, regardless of the
thread count.

### Duplicate listing

#### `--list-duplicates`

List any duplicated papers, or citation keys, in the [BibTeX] database.

#### `--list-papers`

List duplicate papers only, including possible title-and-author matches

Two entries are treated as the same paper if they share a DOI, an MR number
or an arXiv identifier. As a fallback, entries whose normalized titles and
author lists (surnames and first initials) agree are reported as *possible*
duplicates. Entries linked through a chain of such matches are grouped
together. The same rules are used by `--check`, `--remove-duplicate-papers`
and `--deduplicate`.

#### `--list-keys`

List repeated citation keys only

### Duplicate cleanup

#### `--deduplicate`

Remove duplicate papers and rename repeated citation keys

This offline cleanup first removes repeated papers, then renames repeated
keys among the remaining entries. As usual, the updated file is written
to `updated_file.bib` unless `--overwrite` is used.
Existing fields and formatting are preserved; missing fields are added from
later copies. Ignored-field, font-conversion and wrapping options do not apply
to cleanup. Cleanup cannot be combined with listing options or `--check`, and
the lookup options (`-m`, `-M`, `-n`, `-a` and `-x`) are ignored.

#### `--remove-duplicate-papers`

Remove repeated papers, keeping the first occurrence in file order

Papers are matched as described under `--list-papers`. Title-and-author
matching is heuristic, so inspect the output of `--list-papers` before
removing entries.

The first entry is the base. Missing fields are copied from later entries in
file order. Existing fields, including empty fields, are kept; if several copies
supply the same missing field, the first value wins. Field expressions and
macros are copied without expansion. Each removal reports the removed key and
the retained key, with source lines. Literal `crossref`, `xref`, `related`,
`entryset` and `xdata` references inside the bibliography are updated where
the mapping is unambiguous. Use `-t` to update citations in external [LaTeX]
files; otherwise these must be updated manually.

#### `--rename-duplicate-keys`

Rename repeated keys without deleting papers. The first occurrence of each
key is kept. Duplicated key names are replaced with a key formed
from the authors' surnames and the year, for example `AcharRiche2019`.
Editors' names are used if there are no authors. If necessary, a suffix
of `a`, `b`, ..., `z`, `aa`, etc. is added to ensure that the key names
are unique.

Using `--remove-duplicate-papers` together with `--rename-duplicate-keys` is equivalent
to `--deduplicate`.

#### `--merge`

Merge two or more BibTeX files, removing duplicate papers and keys

The input files must have a `.bib` extension and are processed in the
order given. When removing duplicates, the rules used by `--deduplicate`
apply: the first copy of each paper and key is kept, and any repeated
keys are renamed using the authors' names and the publication year.
Fields missing from the first copy are added from
later entries, with earlier values having precedence. Retained entries,
comments, preambles and string macros keep their original formatting;
macros are not expanded for duplicate matching.

Merging is offline and cannot be combined with `--check` or duplicate
listing options.

By default, the merged [BibTeX] file is written to `merged_first.bib` if 
the first [BibTeX] file is called `first.bib`. Use `--output` to
write to a different filename, or `--overwrite` to overwrite the
first [BibTeX] file, which will be backed up with a `.bak` extension.

    bibupdate --merge first.bib second.bib --output combined.bib
    bibupdate --merge first.bib second.bib -t paper.tex --output combined.bib

Use `-t`/`--texfile` to update unambiguous citations in associated [LaTeX]
files, which are backed up with `.bak` extensions.

#### `-t, --texfile FILE.tex [FILE.tex ...]`

Update citation keys in the listed [LaTeX] files when cleaning duplicate entries

This option requires `--merge`, `--deduplicate`, `--remove-duplicate-papers` or
`--rename-duplicate-keys`. The `.tex` and `.bib` extensions distinguish the
TeX files from the bibliography and optional output file, for example:

    bibupdate --deduplicate -t chapter.tex appendix.tex papers.bib

Only unambiguous citation key mappings are applied to the [LaTeX] files.
If different papers share a key, citations of that key in the [LaTeX] files
are left unchanged and a warning is printed. The later papers are given new
unique keys in the merged [BibTeX] file.

Standard literal citation commands such as `\cite`, `\citep`, `\nocite`,
`\parencite` and `\textcites` are supported, including optional notes and
comma-separated key lists. Comments, verbatim text and other commands are
preserved. Custom citation macros are not expanded, and included files are
only processed if explicitly listed.

Before changing a TeX file, its original contents are saved with a `.bak`
extension, for example `chapter.tex.bak`. Unchanged files are not rewritten
or backed up. Existing backups of changed files are replaced.

### Output and formatting

#### `--output FILE.bib`

Write the bibliography to the specified file

Use this option to specify the name of the new [BibTeX] output file. An
existing non-empty output file is first backed up with a `.bak` extension.
This option cannot be combined with `--overwrite`, or with an output file
given as a second positional argument.

#### `-o, --overwrite`

Overwrite the existing [BibTeX] file with the updated version. The original
file is first backed up with a `.bak` extension. This option cannot be
combined with `--output`.

#### `-i FIELDS, --ignored-fields=FIELDS`

A space-separated list of [BibTeX] fields to omit when writing the updated
[BibTeX] file

By default [bibupdate] removes the following fields from each [BibTeX] entry:

- `coden`
- `mrreviewer`

The `-i` option replaces this default list. Repeated `-i` options are combined;
field names are case-insensitive and separated by spaces. An empty string keeps
every field:

    bibupdate -i "coden fjournal" file.bib   # ignore coden and fjournal
    bibupdate -i coden -i fjournal file.bib  # ignore coden and fjournal
    bibupdate -i "" file.bib                 # do not ignore any fields

#### `-k, --keep-fonts`

Use `-k` to retain legacy LaTeX font names in titles. By default, the
following font substitutions are automatically applied:

- `\Bbb X` --> `\mathbb{X}`
- `\scr X` --> `\mathcal{X}`
- `\germ X` --> `\mathfrak{X}`

This applies both to input titles and to titles retrieved from AMS.

#### `-w LEN, --wrap LEN`

Wrap [BibTeX] fields to specified width

By default, lines are not wrapped (a wrap length of `0`). A positive
wrap length `LEN` wraps each field value to that width, with a tab before
continuation lines.

### Reports and logging

#### `-q, --quiet`

Print fewer messages

By default, [bibupdate] prints a compact reference for each paper that
is updated, and a warning for each paper for which the AMS lookup fails.
With `-q` (or `--quiet`) only a one-line message is printed for updated
papers, together with the warnings for failed lookups. With `-qq` only errors
are printed. Failed lookups are printed in red when the output is a terminal.

#### `-l LOG, --log LOG`

Log output to file (defaults to stdout)

By default, reports and warnings go to standard output. Use `-l` to write
them to a file. Existing log files are overwritten. Fatal errors are always
printed to standard error.

### Help and version

#### `-h, --help`

Print a short list of command-line options

#### `-H, --Help`

Print the full-help message

## Known issues

- **BibTeX syntax:** the parser uses regular expressions rather than a full
  BibTeX grammar. Use brace-delimited entries with one field per line and
  braced values or simple words. Multiple fields on one line, quoted
  values, `#` concatenation, string-macro expansion, and
  fields containing `@` or `={...}` can be misread or omitted. Inspect the
  output carefully when using these forms. Duplicate listing and cleanup use
  a source scanner that preserves quoted and nested values, comments and macros;
  macros are not expanded for duplicate matching.
- **Title matching:** capitalization braces and apostrophes are removed before
  searching and comparing. Mathematics is also removed, which can make distinct
  titles look similar. TeX commands and accents are not fully decoded, so
  equivalent spellings can still fail to match. A unique fuzzy title match is
  a heuristic, not a guarantee that a paper has been correctly identified.
- **Author names:** [mrlookup] uses only the first author's surname. A compound
  surname is preserved in `surname, given names` form; without a comma, only
  the last word is used. Accents, name particles and alternative spellings can
  therefore affect searches.
- **Page numbers:** numeric ranges and single numeric pages are supported.
  Article identifiers and prefixed page numbers are not handled reliably.
  When only non-numeric page numbers are given, the title is used
  instead. For non-book entries the year is then omitted from the query.
- **Ambiguous or missing results:** an AMS entry is updated only when
  there is a unique match. [BibTeX] entries are not changed when no
  matches, or multiple matches, are found. Entries without a usable title
  are more likely to receive an incorrect match. By default, skipped
  entries, such as those with an existing `mrnumber`, are never changed.
- **arXiv searches:** searches use significant title words and examine at most
  ten results. Titles dominated by mathematics or short words are more
  likely to receive false matches. As with [mrlookup] searches, the [arXiv]
  fields for a paper are updated only if there is a unique match.
- **Network services:** connections can fail, time out or return unexpected
  data. Requests use a 30-second timeout. Connection errors and
  timeouts produce warnings, and processing continues. A missed lookup does
  not prove that the paper is absent from the database.

## Tests

The files in `tests/` contain automated checks to catch bugs after changes:

- [test_mrlookup.py](tests/test_mrlookup.py): paper searches and updates,
  including title braces and author names.
- [test_duplicates.py](tests/test_duplicates.py): duplicate listing, paper removal,
  collision-free key renaming and preservation of bibliography source text.
- [test_merge.py](tests/test_merge.py): multi-file merging, duplicate cleanup,
  citation remapping and output backups.
- [test_tex_citations.py](tests/test_tex_citations.py): TeX citation remapping,
  ambiguous keys and backups during duplicate cleanup.
- [test_threads_output.py](tests/test_threads_output.py): parallel lookups,
  output formatting, colours, and quiet/check modes.
- [test_documentation.py](tests/test_documentation.py): documentation generation
  and preservation of handwritten manual text.
- [test_ctan.py](tests/test_ctan.py): release archive contents and CTAN upload
  metadata generation.
- [test_settings.py](tests/test_settings.py): metadata discovery through symlinks
  and standalone operation without an ini file.
- [test_release.py](tests/test_release.py): release readiness checks and failure
  handling before packaging.

Run all tests from the project directory:

```bash
python3 -m unittest discover -s tests -v
```

The tests use simulated lookup responses, so no network access is needed.
Documentation checks require Pandoc and latexmk to be available.

## Rebuilding the documentation

The built-in help in `bibupdate.py` is the source for `README.md` and the
marked, generated regions of the manual. The title page, styling and text
outside those regions can be edited directly.

Run `python3 setup.py readme` in the source directory to refresh both sources
and compile `bibupdate.pdf`. This requires Python, Pandoc, and `latexmk` from
a TeX distribution. Use `--no-pdf` to refresh only the sources; `docs` is an
alias for `readme`. BibUpdate itself remains a self-contained Python script
with no non-standard dependencies.

## Preparing a release

From a source checkout, update `bibupdate.ini`, the script's embedded
`default_metadata` and copyright notice, and the first heading of 
`CHANGES.md`. The changelog heading must name the release version:

```bash
**v2.0** -- CTAN release
```

and headings such as

```bash
## Version 2.0.0 - 2026-11-02
```

are both accepted. A zero patch component may be omitted in the changelog. Any
date in the heading must match the ini file. Release versions in the ini file
must be `X.Y.Z`, without a prerelease suffix, and the copyright end year must
match the release year. Rebuild the documentation and commit the
prepared files using:

```bash
make_release
usage: setup.py [-h] [-c] [-f] [-s] [-m] [-t]

Check release readiness and build the CTAN archive, or run only the requested maintenance actions (-m/-t).

options:
  -h, --help        show this help message and exit
  -c, --check-only  check release readiness without packaging
  -f, --force       force building bibupdate.tar.gz
  -s, --skip-tests  skip the test suite
  -m, --manual      rebuild README.md and the manual (combine with -t)
  -t, --tests       run the test suite (combine with -m)
```

Functionally, `make_release` is equivalent to running commands like:

```bash
python3 setup.py readme
# Review and commit the release changes, then:
python3 setup.py release
```

`./make_release` runs the same release command. It checks metadata consistency,
the changelog, a clean Git working tree (including untracked files), generated
documentation, PDF freshness and metadata, the [LaTeX] log, and all tests before
creating `bibupdate.tar.gz` and `bibupdate.ctan`. Checks use Pandoc and `pdfinfo`;
rebuilding the manual also needs latexmk and TeX. The release check does not
change metadata or rebuild files automatically.
Terminal reports use green ticks for passing checks and test summaries, red
crosses and text for failures, and yellow notices for skipped tests or overrides.
Redirected output contains no colour escape sequences.

Use `./make_release -m` (or `--manual`) to rebuild the README and manual only,
`./make_release -t` (or `--tests`) to run the tests only, or `./make_release -mt`
to do both. Manual builds always recompile `bibupdate.tex`, even if latexmk
considers the PDF current. These actions do not run readiness checks or create
an archive, so they also work while preparing an uncommitted release. They cannot
be combined with the release-only flags below. The same options are available
with `python3 setup.py release`.

Use `-c` or `--check-only` to inspect readiness without creating an archive, `-s` or
`--skip-tests` to omit the test suite, and `-f` or `--force` to building
the tar file. Missing or changed package files still prevent the tar
file from being created. The option `--check-only` returns a nonzero exit
status when any check fails, including with `--force`.

`python3 setup.py ctan` packages the existing release files without readiness
checks. Both commands prepare files locally; upload separately using
`ctanupload -F bibupdate.ctan` from the source directory.

## Licence

Andrew Mathas

GNU General Public License, Version 3, 29 June 2007

[bibupdate] Version 2.1.0. Copyright (C) 2012-2026

This program is free software: you can redistribute it and/or modify it under
the terms of the GNU General Public License ([GPL]) as published by the Free
Software Foundation, either version 3 of the License, or (at your option) any
later version.

This program is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
PARTICULAR PURPOSE. See the GNU General Public License for more details.

[BibTeX]: http://www.bibtex.org/
[mrlookup]: https://mathscinet.ams.org/mathscinet/freetools/mrlookup
[MathSciNet]: https://mathscinet.ams.org/mathscinet/publications-search
[MRef]: https://mathscinet.ams.org/mathscinet/freetools/mref
[bibupdate]: https://github.com/AndrewMathas/BibUpdate
[arXiv]: http://arxiv.org/
[LaTeX]: https://latex-project.org/
[GPL]: http://www.gnu.org/licenses/gpl.html
