Command Line Interface

The bibdeskparser command-line tool exposes the public Library API as subcommands, so that a BibDesk .bib database can be inspected and modified from the shell without writing Python code. The bibdeskparser script is installed together with the package (e.g. via pip install bibdeskparser); to install just the command-line tool on your PATH, without adding the package to a Python environment, use uv tool install bibdeskparser.

The command-line tool is also the project’s intended integration surface for AI coding agents: an agent that can run shell commands can work with a BibDesk library through one-shot bibdeskparser invocations, guided by the --help output alone (see How to give an AI coding agent access to your library).

Usage

$ bibdeskparser <command> [BIBFILE] <args> <options>

Run bibdeskparser --help for the list of commands, bibdeskparser <command> --help for the arguments and options of a specific command, and bibdeskparser --version for the installed version.

Every command operates on a single .bib file, given as the first argument after the command name. An argument counts as the BIBFILE exactly if it does not start with - and ends in .bib (case-insensitive). When the BIBFILE is omitted, the file named by the default_bib_file option of a discovered bibdeskparser.toml is used instead; the configuration file is discovered relative to the current working directory, falling back to the XDG location (see Configuration). With neither a BIBFILE argument nor a configured default_bib_file, the command fails with a usage error. The .bib file must already exist for every command except create, which starts a new, empty library.

The commands are named after the corresponding Library methods and properties (import corresponds to import_bibtex(), since import is a Python keyword). Operations that the Python API expresses through dict-like access map to commands as follows: set_group/delete_group assign to and delete from groups, set_string/delete_string assign to and delete from strings, show/keys/delete correspond to indexing, iterating over, and del on the library itself, and fields/get_field/set_field/delete_field correspond to iterating over, indexing, assigning to, and del on a single Entry (its fields). Commands that read one entry’s derived data – author, editor, groups KEY, keywords KEY – correspond to the same-named Entry properties, and set_type assigns entry_type.

Read-only commands print their result to stdout. Mutating commands load the library, apply the change, save the file back in place, and print nothing on success – except rekey without NEW_KEY and rename_file without NEW, which print the generated key or file path, as does add_file when it auto-files, and import/add, which print the citation keys of the added entries (add --dry-run only prints the fetched entry, without modifying the file). add_abstract prints a per-key report of the fetched abstracts (with --dry-run, without modifying the file).

JSON output

Every command that prints structured data (all read-only commands except render and export) accepts a --json flag to print the data as JSON instead of human-readable text, for consumption by other tools:

$ bibdeskparser show tests/Refs/refs.bib GoerzA2023 --field doi,volume --json
{
  "GoerzA2023": {
    "doi": "10.3390/atoms11020036",
    "volume": "11"
  }
}

Errors and exit codes

A successful command exits with code 0. Invalid command-line usage (unknown command, missing argument, no BIBFILE and no default_bib_file) exits with code 2. Any error reported by the underlying library – an unknown citation key or group name, an invalid value, a missing file, or a StaleFileError when the .bib file changed on disk while being edited – prints a one-line Error: <message> on stderr and exits with code 1, without a traceback.

Creating a library

create

Create BIBFILE as a new, empty library: a .bib file containing only the standard BibDesk header comment. Corresponds to saving a from-scratch Library (Library().save(path)). Unlike for every other command, the file must not already exist; an existing file is never overwritten.

$ bibdeskparser create new.bib

All other commands require the .bib file to exist, so a new library is started with create and then filled with entries:

$ bibdeskparser create new.bib
$ bibdeskparser import new.bib entries.bib

With a default_bib_file configured in bibdeskparser.toml (see Configuration), bibdeskparser create without an argument creates that file, bootstrapping the configured library.

Inspecting

keys

List citation keys, one per line. See keys(). With --json: an array of strings.

$ bibdeskparser keys tests/Refs/refs.bib --type book
Shapiro2012
BrumerShapiro2003
Tannor2007
MATLAB:2014

Without options, every entry is listed. Filter options narrow the list: an entry is listed if it matches one of the (repeatable) --type TYPE values (if any are given) and satisfies every --has FIELD, --missing FIELD, and --empty FIELD filter. For any field, exactly one of the three field predicates holds: --has requires the field to be defined with a non-empty value, --missing requires it to not be defined at all, and --empty requires it to be defined, but with an empty value – a defined-but-empty field is neither “missing” nor “has”. Types and field names are matched case-insensitively.

$ bibdeskparser keys tests/Refs/refs.bib --type article --missing eprint
WinckelIP2008
TuriniciHAL00640217
Vecheck2022.09.09.507322

duplicate_keys

List citation keys that occur more than once, one per line. See duplicate_keys. With --json: an array of strings.

$ bibdeskparser duplicate_keys tests/Refs/with_duplicates.bib
GoerzSPP2019

show [KEY...]

Show the data of one or more entries: a KEY (entry_type) heading, the raw fields, and derived data (groups, keywords, files, URLs, and dates). Corresponds to indexing the library, lib[key]. With --json: an object mapping each key to an object with entry_type, key, fields, groups, keywords, files, urls, date_added, and date_modified.

--field FIELD narrows the output to the named fields (repeatable and comma-separated, case-insensitive), dropping the derived data; a field not defined on an entry is silently omitted. With --json, this yields a flat {key: {field: value}} map – convenient for backfilling missing metadata.

Keys come from the KEY arguments and/or --keys-from FILE (one key per line; - reads standard input), so the output of another command can be piped straight in. By default an unknown key aborts the command with an error and no output; --skip-missing instead reports each miss on stderr and shows the remaining entries.

$ bibdeskparser show tests/Refs/refs.bib GoerzDiploma2010
GoerzDiploma2010 (mastersthesis)
    author:   Goerz, Michael
    keywords: OCT, Quantum Gates, Ultracold Atoms
    school:   Freie Universität Berlin
    title:    Optimization of a Controlled Phasegate for Ultracold Calcium Atoms in an Optical Lattice
    type:     {Diplomarbeit}
    url:      https://michaelgoerz.net/research/diploma_thesis.pdf
    year:     2010
  groups:        My Papers
  keywords:      OCT, Quantum Gates, Ultracold Atoms
  urls:          https://michaelgoerz.net/research/diploma_thesis.pdf
  date added:    2026-07-18T07:49:28-04:00
  date modified: 2026-07-18T11:43:24-04:00

For example, to inspect the DOI and title of every entry that is missing an eprint field, in one pipeline:

$ bibdeskparser keys --missing eprint \
    | bibdeskparser show --field doi,title --json --keys-from -

fields KEY

List the names of the fields defined on an entry, one per line. Corresponds to iterating over an Entry. This covers the normal BibTeX fields, including keywords, but not the internal date and bdsk-* fields; use show for a complete view of an entry. With --json: an array of strings.

$ bibdeskparser fields tests/Refs/refs.bib Evans1983
author
keywords
note
title
url
year

get_field KEY FIELDNAME

Print the value of one field of an entry. Corresponds to indexing an Entry, lib[key][fieldname]; field names are case-insensitive. A field whose value is a reference to an @string macro prints as the bare macro name (see strings for the definitions). Fails for a field not defined on the entry (see fields). With --json: a string.

$ bibdeskparser get_field tests/Refs/refs.bib GoerzJPB2011 title
The quantum speed limit of optimal controlled phasegates for trapped neutral atoms

author KEY, editor KEY

Show the authors (editors) of an entry as structured names, one per line, in last-name-first form (von Last, Jr, First). See author and editor. An entry without the corresponding field prints nothing. With --json: an array of objects with first, von, last, and jr keys, each an array of name words.

$ bibdeskparser author tests/Refs/refs.bib Shapiro2012
Shapiro, Moshe
Brumer, Paul
$ bibdeskparser author tests/Refs/refs.bib KochJPCM2016 --json
[
  {
    "first": [
      "Christiane",
      "P."
    ],
    "von": [],
    "last": [
      "Koch"
    ],
    "jr": []
  }
]

search QUERY

List the keys of the entries matching QUERY, best match first, one per line. See search(). With --json: an array of keys.

The query is matched against the stored field values (bare @string macro names intact), the decoded Unicode values, and macro expansions. --field FIELD (repeatable) limits the search to the given fields; the special name key matches against the citation key. --match sets the match strictness (the levels up to fuzzy match everything from the previous level and are case-insensitive; regex follows standard re semantics):

  • exact: the query occurs verbatim as a substring.

  • folded: additionally ignores accents (Schrodinger and Schroedinger both find Schrödinger).

  • words (the default): additionally matches when most of the query’s words occur in a field, in any order.

  • fuzzy: additionally tolerates small typos in individual words.

  • regex: the query is a regular expression (case-sensitive unless the pattern says (?i)).

$ bibdeskparser search tests/Refs/refs.bib "Schroedinger" --field title
WP_Schroedinger

groups [KEY]

Without KEY, list all static groups and the keys they contain. See groups. With --json: an object mapping each group name to an array of keys.

$ bibdeskparser groups tests/Refs/refs.bib
Diploma: Tannor2007, NielsenChuangCh10QEC, Evans1983, LapertPRA09
My Papers: GoerzDiploma2010, GoerzJPB2011, GoerzNJP2014, GoerzPRA2014, GoerzPhd2015, GoerzPRA2015, GoerzEPJQT2015, GoerzNPJQI2017, GoerzQST2018, GoerzSPP2019, GoerzSPIEO2021, GoerzQ2022, GoerzA2023

With KEY, list the names of the groups that entry belongs to, one per line (groups; with --json: an array of strings):

$ bibdeskparser groups tests/Refs/refs.bib GoerzQ2022
My Papers

keywords [KEY]

Without KEY, list all keywords and the keys of the entries using them. See keywords. With --json: an object mapping each keyword to an array of keys.

$ bibdeskparser keywords tests/Refs/refs.bib
OCT: BrifNJP2010, KochJPCM2016, SolaAAMOP2018, MorzhinRMS2019, ...
Coherent Control: BrifNJP2010, Shapiro2012, SolaAAMOP2018, ...
...

With KEY, list the keywords of that entry, one per line (keywords; with --json: an array of strings):

$ bibdeskparser keywords tests/Refs/refs.bib LapertPRA09
Filtering
OCT

strings

List all @string macro definitions. See strings. With --json: an object mapping each macro name to its value. With --bib (mutually exclusive with --json): re-parseable @string{name = {value}} lines, sorted by name – exactly the text that edit_strings presents in the editor, and thus the baseline for a non-interactive edit_strings --stdin round trip.

$ bibdeskparser strings tests/Refs/refs.bib
atoms = Atoms
epjd = Eur. Phys. J. D
epjqt = EPJ Quantum Technol.
...
$ bibdeskparser strings tests/Refs/refs.bib --bib
@string{atoms = {Atoms}}
@string{epjd = {Eur. Phys. J. D}}
...

timestamp

Print the save timestamp from the file header, in ISO 8601 format (or nothing, if the header has no timestamp). See timestamp. With --json: a string or null.

$ bibdeskparser timestamp tests/Refs/refs.bib
2026-07-18T16:02:00-04:00

eval_format_spec KEY [FORMAT]

Print the citation key that a format in the format-specifier language yields for the entry at KEY, via eval_format_spec() – without renaming anything (unlike rekey). FORMAT defaults to the format_spec configured in the [auto_key] table of bibdeskparser.toml (which may map a format per entry type). With --json: a string.

A key that already matches the format evaluates to itself, so any output other than KEY itself flags a nonconforming key:

$ bibdeskparser eval_format_spec tests/Refs/refs.bib LapertPRA09 \
    '%a1%c{journal}0%Y%u0'
LapertPRA2009

With --filename FILE, the format is evaluated as a file name instead, in the file-name dialect; nothing is renamed or moved. FILE only supplies the original-name specifiers %l/%L/%e/%E (e.g. its extension); it need not exist or be attached to KEY, and an empty string selects the dialect when FORMAT uses none of those specifiers. FORMAT then defaults to the [auto_file] format. A preview shows the base name; on-disk collision suffixes are added only by actual filing (rename_file / add_file). If FILE is an attachment’s current path and already matches the format, it prints unchanged:

$ bibdeskparser eval_format_spec tests/Refs/refs.bib Shapiro2012 \
    '%f{Cite Key}%u0%e' --filename shapiro.pdf
Shapiro2012.pdf

Rendering and exporting

render KEY...

Render a formatted citation for one or more entries, via render(). The --format option selects the output format (markdown, the default, tex, or html); --style selects the layout of multiple citations relative to one another (default, paragraphs, numbered list, or itemized list).

$ bibdeskparser render tests/Refs/refs.bib GoerzA2023 --format tex

export KEY...

Export one or more entries as self-contained BibTeX text (including any @string macros they reference), via export(). The --format option selects the export format (default, raw, or minimal); --outfile PATH writes to a file instead of printing to stdout.

$ bibdeskparser export tests/Refs/refs.bib GoerzA2023 --format minimal \
    --outfile out.bib

Entries

rekey OLD_KEY [NEW_KEY]

Change the citation key of an entry, via rekey().

$ bibdeskparser rekey tests/Refs/refs.bib LapertPRA09 LapertPRA2009

Without NEW_KEY, the key is generated from an auto-key format in the format-specifier language – the --format-spec PATTERN option if given, or else the format_spec configured in the [auto_key] table of bibdeskparser.toml (which may map a format per entry type; see the configuration) – and printed to stdout:

$ bibdeskparser rekey tests/Refs/refs.bib LapertPRA09
LapertPRA2009
$ bibdeskparser rekey tests/Refs/refs.bib LapertPRA09 --format-spec '%a1:%Y%u0'
Lapert:2009

A key that already matches the format is kept unchanged, and a %u/%U/%n specifier in the format resolves collisions with the other entries in the library. To preview the generated key without renaming, use eval_format_spec.

delete KEY...

Delete one or more entries from the library. Corresponds to del lib[key].

$ bibdeskparser delete tests/Refs/refs.bib WP_Schroedinger

set_type KEY TYPE

Change the entry type of an entry, e.g. to article (case-insensitive). Corresponds to assigning entry_type. An unrecognized TYPE is rejected; custom entry types can be defined in the types table of bibdeskparser.toml (see the configuration).

$ bibdeskparser set_type tests/Refs/refs.bib Wilhelm2003.10132 unpublished

set_field KEY FIELDNAME VALUE

Set one field of an entry, adding the field if it does not exist. Corresponds to assigning to an Entry, lib[key][fieldname] = value; field names are case-insensitive.

$ bibdeskparser set_field tests/Refs/refs.bib TuriniciHAL00640217 note \
    "Lecture notes for a graduate course"

Like BibDesk, a VALUE that is a valid @string macro name is stored as a bare macro reference rather than as literal text; --literal forces literal text instead (ValueString), and --macro forces a macro reference (MacroString), failing for a VALUE that is not a valid macro name. The keywords, date, and bdsk-* fields cannot be set this way (use add_to_keyword, add_file, add_url, etc.); an author/editor VALUE must be parseable as names. A warning is printed on stderr for a field that is not appropriate for the entry type.

delete_field KEY FIELDNAME

Delete one field from an entry. Corresponds to del lib[key][fieldname]; field names are case-insensitive. Fails for a field not defined on the entry (see fields), and for the keywords, date, and bdsk-* fields (use remove_from_keyword, unlink_file, remove_url, etc. instead).

$ bibdeskparser delete_field tests/Refs/refs.bib GoerzJPB2011 note

Adding entries

import [FILE]

Import the entries of a BibTeX snippet – read from FILE, from standard input (--stdin), or downloaded from a URL (--url URL); exactly one of the three – into the library, via import_bibtex(), and print their citation keys. The snippet may be anything from a single publisher-provided entry to a complete .bib file (including @string definitions, e.g. the output of export).

Every entry is sanitized and normalized on its way in (see import_bibtex() for the full list): the journal becomes an @string macro reference – resolved against the library’s macros and the [journal_macros] configuration, or newly created, with a warning, from the journal’s lowercased initials (literal arXiv:... pseudo-journals excepted); proper nouns in sentence-case titles and all configured protected_words are brace-protected; DOIs are normalized; for articles, page ranges collapse to the first page and non-essential fields are dropped. Citation keys are regenerated from the [auto_key] format if configured, else as e.g. GoerzPRA2014 (articles) or Goerz2205.15044 (arXiv preprints); --keep-keys keeps the incoming keys instead. --fix-uppercase repairs all-uppercase names/titles found in some publisher data.

An entry whose DOI or eprint is already in the library is rejected, and any validation problem in the snippet rejects the whole import, reporting all problems at once, with the .bib file untouched.

$ bibdeskparser import tests/Refs/refs.bib entries.bib
BaumgratzPRL2014
$ pbpaste | bibdeskparser import tests/Refs/refs.bib --stdin
GrapeJMR2005
$ bibdeskparser import tests/Refs/refs.bib --url https://example.com/more.bib
MotzoiPRL2009

Note that the first argument ending in .bib names the library, so importing from a .bib file requires naming the library explicitly (import tests/Refs/refs.bib entries.bib), even with a configured default_bib_file.

add QUERY...

Fetch bibliographic data for QUERY from the appropriate online source and add it to the library as a new, sanitized entry, via add(), printing its citation key. All QUERY arguments are joined into a single query:

  • an arXiv identifier (2205.15044, quant-ph/0106057), or any string containing one (e.g. an arxiv.org URL), is fetched from the arXiv API and added as an @article preprint with a literal journal = {arXiv:...}, eprint, and archiveprefix;

  • a DOI, or a URL containing one (e.g. most publisher article pages), is fetched from Crossref;

  • anything else (free text with spaces) is a Crossref bibliographic search, adding the best match – verify the result!

An arXiv identifier wins over a DOI when the query contains both. The fetched data passes through exactly the same sanitization as import (journal macros, title protection, key generation, duplicate rejection). Crossref works of a type with no BibTeX equivalent (e.g. datasets) are retrieved as publisher BibTeX via DOI content negotiation and imported as-is. Requires network access; the arXiv API’s rate limits are respected automatically.

$ bibdeskparser add tests/Refs/refs.bib 10.1103/PhysRevA.89.032334
MuellerPRA2014
$ bibdeskparser add tests/Refs/refs.bib https://arxiv.org/abs/1801.00862
Preskill1801.00862
$ bibdeskparser add tests/Refs/refs.bib pulser open-source pulse sequences
SilverioQ2022

With --dry-run, the sanitized entry is printed (as re-parseable BibTeX, like export) and the .bib file is not modified – useful to check what a free-text query matched. --fix-uppercase repairs all-uppercase names/titles in the fetched metadata. With --add-abstract, the abstract returned alongside the metadata (the publisher’s Crossref deposit, or the arXiv summary) is stored in the new entry’s abstract field, cleaned to plain-unicode prose; see add_abstract for filling the field afterwards, with more sources. With --add-preprint, arXiv is searched for a preprint matching the new entry, exactly as with add_preprint, whose report goes to stderr here (stdout stays the citation key); the search is skipped when the entry already has an eprint, as one fetched from an arXiv query does. All three options default to the [add] configuration table, and each has a negative form (--no-add-abstract, …) to override a configured true.

$ bibdeskparser add tests/Refs/refs.bib --dry-run 10.22331/q-2022-01-24-629
@string{quant = {Quantum}}

@article{SilverioQ2022,
...

Abstracts and preprints

add_abstract KEY...

Fetch and store missing abstracts for the given entries, via add_abstract(). For each KEY, candidate abstracts are gathered from Crossref (via the entry’s doi), from the text of the entry’s first attached PDF (requires the poppler pdftotext tool on PATH; skipped otherwise), from the arXiv API (via the entry’s eprint), and from Semantic Scholar as a last resort. Each candidate is cleaned to plain-unicode prose (math markup converted to unicode, publisher copyright trailers stripped) and validated with heuristic garble checks, and the best one is stored in the entry’s abstract field – but only if its confidence reaches --min-confidence (high, the default; medium; or low):

  • high: an online abstract identified by the entry’s doi/eprint (and agreeing with the PDF text, where both exist), or an unambiguous PDF extraction;

  • medium: a single unconfirmed source;

  • low: the PDF text and an online source disagree – one of them probably grabbed the wrong text.

The command prints a per-key report. A candidate that was not stored is reported in full, so it can be reviewed and applied manually with set_field. Entries that already have a non-empty abstract are skipped (--overwrite refetches and replaces them); an entry whose abstract is present but empty does not need --overwrite. With --mark-empty, an entry for which no valid abstract is found anywhere gets an empty abstract field, marking it as audited: such entries are matched by keys --empty abstract, no longer by keys --missing abstract. --min-confidence and --mark-empty default to the [add_abstract] configuration table. Requires network access; --dry-run prints the report without modifying the .bib file, and --json maps each key to {abstract, source, confidence, note, applied}.

$ bibdeskparser keys tests/Refs/refs.bib --type article --missing abstract
TuriniciHAL00640217
SauvagePRXQ2020
Vecheck2022.09.09.507322
KatrukhaNC2017
$ bibdeskparser add_abstract tests/Refs/refs.bib \
    SauvagePRXQ2020 Vecheck2022.09.09.507322
SauvagePRXQ2020: stored (crossref, high)
Vecheck2022.09.09.507322: needs review (semanticscholar, medium) [cr-miss]
    Quantum biology examines quantum effects in living cells ...
$ bibdeskparser set_field tests/Refs/refs.bib Vecheck2022.09.09.507322 \
    abstract "Quantum biology examines quantum effects in living cells ..."

add_preprint KEY...

Find and store the matching arXiv preprint for the given entries, via add_preprint(). For each KEY, the arXiv API is searched for a preprint matching the entry (by title and first author, precise queries first) and, on a confident match, its identifier is stored in the entry’s eprint field, along with archiveprefix = arXiv. A result is accepted only when

  • its arXiv DOI equals the entry’s doi field (the strongest signal), or

  • its title is a near-exact match, or

  • a good title match is corroborated by the first author’s last name.

A title-based match whose arXiv submission postdates the entry’s year by more than a year is rejected unless its journal reference names that year – a guard against unrelated papers sharing a generic title. Such a postdated-unverified candidate is only reported; after reviewing it, apply it explicitly with --eprint ID (a single KEY only, no network access; a leading arXiv: prefix and a version suffix are stripped).

The eprint field encodes the entry’s audit state: absent means the preprint status is unknown (keys --missing eprint), empty means a search ran cleanly and found no preprint (keys --empty eprint), non-empty holds the identifier. With --mark-empty (defaulting to the [add_preprint] configuration table), a clean no-match stores that empty marker, so repeated fill-in runs skip the entry. Entries that already have a non-empty eprint are skipped (--overwrite re-searches and replaces); the empty marker is re-searched without --overwrite. On a failed search (network/API error) the entry is never modified, so a re-run picks it up.

The command prints a per-key report; --dry-run prints it without modifying the .bib file, and --json maps each key to {eprint, match, ratio, note, applied}. Requires network access (except with --eprint) and respects the arXiv API’s rate limit of one request every three seconds, so large runs take time.

$ bibdeskparser keys tests/Refs/refs.bib --type article --missing eprint
WinckelIP2008
TuriniciHAL00640217
Vecheck2022.09.09.507322
$ bibdeskparser add_preprint tests/Refs/refs.bib --mark-empty \
    WinckelIP2008 Vecheck2022.09.09.507322
WinckelIP2008: no preprint found (stored empty marker) [best-ratio=0.42]
Vecheck2022.09.09.507322: no preprint found (stored empty marker) [best-ratio=0.31]

Groups

add_to_group NAME KEY...

Add entries to the static group NAME, via add_to_group().

$ bibdeskparser add_to_group tests/Refs/refs.bib Diploma GoerzDiploma2010

remove_from_group NAME KEY...

Remove entries from the group NAME, via remove_from_group().

$ bibdeskparser remove_from_group tests/Refs/refs.bib Diploma GoerzDiploma2010

set_group NAME [KEY...]

Create the static group NAME with exactly the given entries, or replace its membership if it already exists. With zero keys, the group is created (or emptied) with no members. Corresponds to lib.groups[name] = keys (see groups).

$ bibdeskparser set_group tests/Refs/refs.bib "To Read" \
    BrifNJP2010 KochEPJQT2022

delete_group NAME

Delete the static group NAME; the entries themselves are not affected. Corresponds to del lib.groups[name].

$ bibdeskparser delete_group tests/Refs/refs.bib "To Read"

Keywords

add_to_keyword KEYWORD KEY...

Add KEYWORD to the given entries, via add_to_keyword().

$ bibdeskparser add_to_keyword tests/Refs/refs.bib Review BrifNJP2010

remove_from_keyword KEYWORD KEY...

Remove KEYWORD from the given entries, via remove_from_keyword().

$ bibdeskparser remove_from_keyword tests/Refs/refs.bib Review BrifNJP2010

Strings (macros)

set_string NAME VALUE

Define or redefine the @string macro NAME. Corresponds to lib.strings[name] = value (see strings).

$ bibdeskparser set_string tests/Refs/refs.bib prl "Phys. Rev. Lett."

delete_string NAME

Delete the @string macro NAME (which must not be referenced by any entry). Corresponds to del lib.strings[name].

$ bibdeskparser delete_string tests/Refs/refs.bib prl

rename_string OLD NEW

Rename the @string macro OLD to NEW, updating every entry that references it, via rename_string().

$ bibdeskparser rename_string tests/Refs/refs.bib quant quantum

Files

add_file KEY FILENAME

Attach the file FILENAME to the entry KEY, via add_file(). By default, FILENAME must exist on disk; pass --no-check-exists to skip that check.

$ bibdeskparser add_file tests/Refs/refs.bib Shapiro2012 papers/shapiro-brumer.pdf

When auto-filing is in effect, the file is not attached under its original name: it is moved into the auto-file location, renamed according to a file-name format in the format-specifier language, and the stored path (relative to the .bib file) is printed to stdout. Auto-filing is in effect when --location DIR or --format-spec PATTERN is given (each defaulting the other to the [auto_file] configuration; see the configuration), or when the configuration sets file_automatically = true; pass --no-auto-file to force a plain attach regardless of the configuration:

$ bibdeskparser add_file tests/Refs/refs.bib Shapiro2012 \
    ~/Downloads/9780471973461.pdf \
    --format-spec '%f{Cite Key}%u0%e' --location Papers
Papers/Shapiro2012.pdf

replace_file KEY OLD NEW

Replace the entry’s attached file OLD with NEW, via replace_file(). Pass --remove to also delete the old file from the filesystem, and --no-check-exists to not require NEW to exist on disk.

$ bibdeskparser replace_file tests/Refs/refs.bib GoerzJPB2011 \
    GoerzJPB2011.pdf corrected.pdf --remove

rename_file KEY OLD [NEW]

Rename (or move) the entry’s attached file OLD to NEW on the filesystem, updating every entry that links it, via rename_file().

$ bibdeskparser rename_file tests/Refs/refs.bib MorzhinRMS2019 \
    MorzhinRMS2019.pdf Reviews/MorzhinRMS2019.pdf

Without NEW, the target is generated by auto-filing: the file is moved into the auto-file location and renamed according to a file-name format in the format-specifier language – the --format-spec PATTERN and --location DIR options if given, or else the format_spec and location keys of the [auto_file] table of bibdeskparser.toml (see the configuration) – and the new path (relative to the .bib file) is printed to stdout:

$ bibdeskparser rename_file tests/Refs/refs.bib GraceJMO2007 grace_jmo_2007.pdf
GraceJMO2007.pdf

A file whose name already matches the format is left in place (re-filing is idempotent), and the format’s %u/%U/%n specifier resolves collisions with existing files. To preview the generated path without moving anything, use eval_format_spec --filename.

URLs

add_url KEY URL

Add URL to the entry KEY, via add_url().

$ bibdeskparser add_url tests/Refs/refs.bib WattsPRA2015 \
    https://arxiv.org/abs/1412.7347

replace_url KEY OLD NEW

Replace the entry’s URL OLD with NEW, via replace_url().

$ bibdeskparser replace_url tests/Refs/refs.bib GoerzDiploma2010 \
    https://michaelgoerz.net/research/diploma_thesis.pdf \
    https://michaelgoerz.net/diploma_thesis.pdf

remove_url KEY URL

Remove URL from the entry KEY, via remove_url().

$ bibdeskparser remove_url tests/Refs/refs.bib WattsPRA2015 \
    https://arxiv.org/abs/1412.7347

Free-form editing

The edit and edit_strings commands accept arbitrary edits as BibTeX text – interactively through $EDITOR, or non-interactively by piping the edited text to --stdin. Neither command ever blocks without a terminal: invoked with no TTY on stdin and with neither --stdin nor an explicit --editor, they fail immediately with a usage error rather than hanging on $EDITOR.

edit KEY...

Edit one or more entries (as BibTeX text) and merge the changes back into the library, via edit(). The --format option (default, raw, or minimal) controls how the entries are presented; --editor CMD overrides the editor command (which defaults to $EDITOR).

$ bibdeskparser edit tests/Refs/refs.bib GoerzQ2022 --editor vim

With --stdin (mutually exclusive with --editor), the full edited text is read from standard input instead of opening an editor. The text to edit is exactly what export prints for the same keys, so any pipeline that transforms the exported text works; piping it back unchanged is a no-op:

$ bibdeskparser export tests/Refs/refs.bib GoerzQ2022 \
    | sed 's/Semi-Automatic/Semiautomatic/' \
    | bibdeskparser edit tests/Refs/refs.bib GoerzQ2022 --stdin

Empty input to --stdin is a usage error (so an accidental < /dev/null cannot silently apply a no-op edit), and text that fails validation – an unparseable block, or a reference to an undefined @string macro – exits with code 1 and the list of problems on stderr, leaving the .bib file untouched.

edit_strings

Edit the @string macro definitions and merge the changes back into the library, via edit_strings().

$ bibdeskparser edit_strings tests/Refs/refs.bib

With --stdin, the edited definitions are read from standard input; the baseline text comes from strings --bib:

$ bibdeskparser strings tests/Refs/refs.bib --bib \
    | sed 's/EPJ Quantum Technol./EPJ Quantum Technology/' \
    | bibdeskparser edit_strings tests/Refs/refs.bib --stdin