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 full list of commands, bibdeskparser <command> --help for the arguments and options of a specific command, and bibdeskparser --version for the installed version. bibdeskparser --usage (or bibdeskparser with no command) prints a short usage summary listing just the command names, without the full --help output.
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). The dict-like operations of the Python API 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, set_info/delete_info assign to and delete from info, show/keys/delete index, iterate over, and del on the library itself, and fields/get_field/set_field/delete_field do the same on a single Entry. The commands that read an entry’s derived data (author, editor, files, urls, groups, keywords) correspond to the same-named Entry properties (groups --index / keywords --index read the inverse groups / keywords mappings), and set_type assigns entry_type. The one command with no API counterpart is config_path, which reports the discovered configuration file.
Read-only commands print their result to stdout; so does export, which only writes a file when asked to, with --outfile or --update (the latter rewrites a previously exported file, never the library itself). Mutating commands load the library, apply the change, save the file in place, and print nothing on success. Two of them can also touch files on disk: rekey moves asset files and key-named attachments along with the key change, and delete can remove an entry’s files. The exceptions that do print: rekey without NEW_KEY and rename_file without NEW print the generated key or file path, as does add_file when it auto-files; import and add print the citation keys of the added entries (add --dry-run prints the fetched entry without modifying the file); and add_abstract, add_preprint, and add_doi print a per-key report of the fetched abstracts, arXiv identifiers, and DOIs (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. The check command additionally exits with code 1, after printing its report, when any audit finds a problem.
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 --file 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(). Without options, every entry is listed; otherwise an entry is listed when it matches one of the --type values (if any) and satisfies every other filter. Types and field names match case-insensitively, group names case-sensitively.
$ bibdeskparser keys tests/Refs/refs.bib --type book
Shapiro2012
BrumerShapiro2003
Tannor2007
MATLAB:2014
Options
--type TYPE– keep only entries of this type (repeatable; an entry matches any listed type).--has FIELD– keep only entries where FIELD has a non-empty value (repeatable).--missing FIELD– keep only entries where FIELD is missing (repeatable). An empty field counts as missing, since BibDesk deletes empty fields on save (see Empty fields).--group NAME/--not-group NAME– keep only entries that are, or are not, members of the static group NAME (repeatable). An unknown group name is an error.--with-files/--without-files– keep only entries that have at least one attachment, or none. Default: no attachment filter.--json– print the keys as a JSON array of strings.
$ bibdeskparser keys tests/Refs/refs.bib --type article --missing eprint
WinckelIP2008
$ bibdeskparser keys tests/Refs/refs.bib --type book --group Diploma
Tannor2007
$ bibdeskparser keys tests/Refs/refs.bib --type article --without-files
ImamogluPRE2015
Luc-KoenigEPJD2004
SauvagePRXQ2020
KatrukhaNC2017
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
check [KEY...]
Run the standing audits and report every problem found, one per line, followed by a PASS/FAIL summary line; the exit code is 0 if all audits pass and 1 otherwise. A read-only pass/fail gate for the library, e.g. after a batch of edits.
$ bibdeskparser check tests/Refs/refs.bib
PASS (61 entries checked)
$ bibdeskparser check tests/test_cli_fail_checks/problems.bib
Duplicate2026: duplicate citation key
MissingDoi2026: missing doi
EmptyDoi2026: missing doi
EmptyDoi2026: empty field 'doi' (BibDesk deletes empty fields on save)
LiteralJournal2026: journal is the literal string 'Some Journal', not an @string macro reference
UndefinedMacro2026: journal references undefined @string macro 'nosuchjournal'
UndefinedField2026: publisher references undefined @string macro 'elsevir'
BadNames2026: author does not parse as names: Cannot split the following name `Doe, John, Jr, X, Y` into parts: Too many commas
MissingRequired2026: missing required field 'year' for entry type 'article'
UnknownType2026: unrecognized entry type 'bogustype'
BadYear2026: year 'August, 2026' does not read as a four-digit year (%Y gives '0')
LiteralMonth2026: month is the literal string 'June', not one of the twelve standard month macros (jan ... dec)
BadMonthMacro2026: month references the macro 'sept', not one of the twelve standard month macros (jan ... dec)
BadMonthMacro2026: month references undefined @string macro 'sept'
UnencodedURL2026: url contains non-ASCII characters: 'https://example.com/münchen' (use 'https://example.com/m%C3%BCnchen')
unused @string macro 'unusedjrnl'
FAIL (16 problems, 14 entries checked)
The audits:
the file parses cleanly (no skipped blocks);
no citation key occurs more than once;
every entry has a recognized entry type and the fields that type requires;
no field is defined but empty (BibDesk deletes empty fields on save; see Empty fields);
every
articlethat is not a preprint has adoi, or is in thedoiknown-missing group;no entry is in a known-missing group for a field it has;
every
journalreferences an@stringmacro, not a literal (a preprint pseudo-journal likearXiv:2205.15044is allowed);no field references an undefined
@stringmacro;every
yearreads as a four-digit year;every
monthis a bare reference to a standard month macro (jan…dec);every
authorandeditorparses as names;no URL-type value (a
url-named field, or abdsk-urllink) holds raw non-ASCII characters;every
@stringmacro is referenced by some entry;no file on disk matches an
[assets]pattern without belonging to an entry (see External Assets; a no-op without an[assets]configuration).
Options
--files– also check that each linked attachment (bdsk-filepath) resolves on disk, matching case exactly. Off by default, since attachments may live only on another machine.--assets– also check that every resolving asset of the[assets]configuration exists on disk. Off by default, like--files.--no-orphans– skip the orphaned-assets audit (on by default).--key-format– also check that each citation key matches its expected auto-key format: the arXiv format for a preprint-only entry, the configured[auto_key]format otherwise.--format-spec PATTERN– check keys against PATTERN instead of the configured format. Implies--key-format.--json– emit{"passed", "entries_checked", "problems": [...]}; each problem hascheck(the failing audit:parse,duplicate_keys,entry_type,required_fields,doi,empty_fields,known_missing,journal,undefined_macro,year,month,names,url_encoding,unused_strings,files,key_format,assets, orasset_orphans),key(ornull), andmessage.
With KEY..., only the given entries are audited and the unused-macro and orphaned-assets audits are skipped; an unknown key is an error.
$ bibdeskparser check tests/test_cli_fail_checks/problems.bib Preprint2026
PASS (1 entry checked)
--files matches case exactly, so it also catches a link whose spelling differs only in case from the file on disk (invisible on a case-insensitive filesystem, broken on a case-sensitive one). It is therefore stricter than the plain existence check behind the save-time warning, and can FAIL a library that would be written without warning.
$ bibdeskparser check tests/Refs/refs.bib --files
PASS (61 entries checked)
$ bibdeskparser check tests/test_cli_fail_checks/deadfiles.bib --files
Dead2020: linked file does not exist: 'Dead2020.pdf'
Case2020: linked file 'case2020.pdf' exists only as 'Case2020.pdf' (case mismatch)
FAIL (2 problems, 2 entries checked)
--key-format flags every key that rekey without NEW_KEY would regenerate differently. A key already matching the format evaluates to itself, so a disambiguated sibling like CollidingPRA2015a still conforms, and an entry lacking a field the format references is audited against the shorter key it generates (Handpicked below has no journal). With no usable format available, a single message is reported rather than one failure per entry.
$ bibdeskparser check tests/test_cli_fail_checks/keyformat.bib --format-spec "%p1%c{journal}0%Y%u0"
Deviation2015: does not match the citation-key format (would be 'DeviationPRA2015')
Handpicked: does not match the citation-key format (would be 'Venueless2015')
FAIL (2 problems, 7 entries checked)
show [KEY...]
Show the data of one or more entries: a KEY (entry_type) heading, the fields, and derived data (groups, keywords, files, URLs, and dates). Corresponds to indexing the library, lib[key], with field values rendered for display. Keys come from the KEY arguments and/or --keys-from; at least one is required.
Options
--field FIELD– show only these fields instead of the full record (repeatable and comma-separated, case-insensitive); the derived data is dropped, and a field not defined on an entry is omitted.--no-unicode– show field values TeX-encoded, as stored, instead of as Unicode text.--no-expand-strings– show a value that references an@stringmacro as the bare macro name (seestrings) instead of the macro’s value.--keys-from FILE– read additional citation keys from FILE, one per line (-for standard input), so another command’s output pipes straight in.--skip-missing– report an unknown key on stderr and show the rest, instead of aborting on the first one.--json– map each key to an object withentry_type,key,fields,groups,keywords,files,urls,date_added, anddate_modified; with--field, a flat{key: {field: value}}map; and under--no-expand-strings, every field value becomes{"macro": <name or null>, "value": <value or null>}.
$ 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 tests/Refs/refs.bib --missing eprint \
| bibdeskparser show tests/Refs/refs.bib --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. Fails for a field not defined on the entry (see fields).
Options
--no-unicode– print the value TeX-encoded, as stored, instead of as Unicode text.--no-expand-strings– print the bare@stringmacro name (seestrings) instead of the macro’s value.--json– print a string; under--no-expand-strings, an object{"macro": <name or null>, "value": <value or null>}.
$ bibdeskparser get_field tests/Refs/refs.bib GoerzJPB2011 title
The quantum speed limit of optimal controlled phasegates for trapped neutral atoms
files [KEY...]
List file attachments (the bdsk-file-N fields), in numeric order within each entry; see files. The output maps each citation key to its attachments (KEY: path, path per line): the given KEY entries (an entry with none maps to an empty list), or every entry with at least one attachment when no KEY is given.
Options
--relative– print each attachment as stored in the.bibfile, relative to its directory, instead of as an absolute path.--flat– print just the paths as one de-duplicated list, sofiles --flatis every file the library references (find the entries missing one withkeys --without-files).--json– print a{key: [paths]}object, or a JSON array with--flat.
$ bibdeskparser files tests/Refs/refs.bib GoerzPRA2014 Shapiro2012 --relative
GoerzPRA2014: GoerzPRA2014.pdf
Shapiro2012:
$ bibdeskparser files tests/Refs/refs.bib --relative --json
{
"BrifNJP2010": [
"BrifNJP2010.pdf"
],
...
}
$ bibdeskparser files tests/Refs/refs.bib GoerzJPB2011 --relative --flat
GoerzJPB2011.pdf
An unknown key is an error. Attachments are modified with add_file, replace_file, unlink_file, and rename_file.
asset NAME [KEY]
Print the path that the asset class NAME – declared as a path pattern in the [assets] table of bibdeskparser.toml – resolves to, via asset(); see External Assets. An entry asset (one whose pattern references entry data) resolves for the entry KEY and requires one; a library asset takes no KEY. Passing the wrong one is an error, as is a NAME that does not resolve at all (not declared, an empty pattern, or a %i document-info key its pattern references that is unset or empty).
Options
--relative– print the path as configured, relative to the.bibfile’s directory, instead of as an absolute path.--no-check-exists– print the path even when nothing is on disk there, which is where a generator should write the asset. By default, a resolved path with nothing there is an error (a directory-valued class requires a directory, any other a file).--json– print the path as a JSON string.
$ bibdeskparser asset fulltext GoerzQ2022 --relative
GoerzQ2022.ingest/fulltext.md
$ bibdeskparser asset topics
/Users/goerz/Documents/Refs/topics.md
$ bibdeskparser asset summary Tannor2007 --no-check-exists
/Users/goerz/Documents/Refs/Tannor2007_summary.md
assets [KEY...]
Report which of the assets declared in the [assets] table exist on disk, via assets(). With KEY..., one line per entry listing its entry assets; without, one line per library asset. A ! prefix marks an asset missing from disk, and an unknown key is an error.
Options
--json– print a{key: {name: bool}}object withKEY..., and a{name: bool}object without.
$ bibdeskparser assets GoerzQ2022 Tannor2007
GoerzQ2022: summary, fulltext, source
Tannor2007: !summary, !fulltext, !source
$ bibdeskparser assets
topics
For coverage over the whole library, pass every key:
$ bibdeskparser assets --json $(bibdeskparser keys)
{
"BrifNJP2010": {
"summary": true,
...
},
...
}
Audit the assets library-wide with check (--assets for missing assets; orphaned assets are audited by default).
urls [KEY...]
List the URLs linked to entries (the bdsk-url-N fields), in numeric order within each entry; see urls. The output shape matches files: each citation key maps to its URLs (KEY: url, url per line), covering the given keys or every entry with at least one linked URL when no key is given.
Options
--flat– print just the URLs as one de-duplicated list.--json– print a{key: [urls]}object, or a JSON array with--flat.
Linked URLs are modified with add_url, replace_url, and remove_url.
$ bibdeskparser urls tests/Refs/refs.bib KochJPCM2016
KochJPCM2016: http://dx.doi.org/10.1088/0953-8984/28/21/213001
search QUERY
List the keys of the entries matching QUERY, best match first, one per line. See search(). The query is matched against the stored field values (bare @string macro names intact), the decoded Unicode values, and macro expansions.
Options
--field FIELD– limit the search to this field (repeatable); the special namekeymatches the citation key.--match LEVEL– set the match strictness (defaultwords). The levels up tofuzzyare case-insensitive, each matching everything the previous one does:exact: the query occurs verbatim as a substring.folded: additionally ignores accents (SchrodingerandSchroedingerboth findSchrödinger) and matches any letter by its plain ASCII spelling (MolmerfindsMølmer).words: additionally matches when most of the query’s words occur in a field, in any order.fuzzy: additionally tolerates small typos; casts the widest net, so verify its results.regex: the query is a regular expression (resemantics, case-sensitive unless it says(?i)).
--json– print the keys as a JSON array.
$ bibdeskparser search tests/Refs/refs.bib "Schroedinger" --field title
WP_Schroedinger
groups [KEY...]
List the static groups each entry belongs to. The output shape matches files: each citation key maps to its group names (see groups), covering the given keys or every entry in at least one group when no key is given.
Options
--flat– print just the group names as one de-duplicated list.--index– print the inverse map instead, from each static group to the keys it contains (seegroups); takes noKEYand lists every group, including empty ones.--json– print the mapping as a JSON object.
$ bibdeskparser groups tests/Refs/refs.bib GoerzQ2022
GoerzQ2022: My Papers
$ bibdeskparser groups tests/Refs/refs.bib --index
Diploma: Tannor2007, NielsenChuangCh10QEC, Evans1983, LapertPRA09
My Papers: GoerzDiploma2010, GoerzJPB2011, GoerzNJP2014, GoerzPRA2014, GoerzPhd2015, GoerzPRA2015, GoerzEPJQT2015, GoerzNPJQI2017, GoerzQST2018, GoerzSPP2019, GoerzSPIEO2021, GoerzQ2022, GoerzA2023
Group membership is modified with add_to_group, remove_from_group, set_group, and delete_group.
keywords [KEY...]
List the keywords each entry is tagged with. The output shape matches files: each citation key maps to its keywords (see keywords), covering the given keys or every tagged entry when no key is given.
Options
--flat– print just the keywords as one de-duplicated list.--index– print the inverse map instead, from each keyword to the keys tagged with it (seekeywords); takes noKEY.--json– print the mapping as a JSON object.
$ bibdeskparser keywords tests/Refs/refs.bib LapertPRA09
LapertPRA09: Filtering, OCT
$ bibdeskparser keywords tests/Refs/refs.bib --index
OCT: BrifNJP2010, KochJPCM2016, SolaAAMOP2018, MorzhinRMS2019, ...
Coherent Control: BrifNJP2010, Shapiro2012, SolaAAMOP2018, ...
...
Keywords are modified with add_to_keyword and remove_from_keyword.
strings
List all @string macro definitions. See strings.
Options
--bib– print re-parseable@string{name = {value}}lines, sorted by name: the baseline foredit_strings--stdin. Mutually exclusive with--json.--json– print an object mapping each macro name to its value.
$ 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}}
...
info [KEY]
Print the document info: the key/value metadata that BibDesk’s “Document Info” panel attaches to the database as a whole (see info and the Document info (the @bibdesk_info block) documentation). Without KEY, print all pairs, one key = value per line; with KEY (matched case-insensitively), print just its value.
Options
--json– print an object mapping each key to its value (withKEY, the value as a JSON string).
$ bibdeskparser info tests/Refs/refs.bib
primary_topics = Coherent Control, Numerics, OCT, Quantum Gates, Ultracold Atoms
$ bibdeskparser info tests/Refs/refs.bib primary_topics
Coherent Control, Numerics, OCT, Quantum Gates, Ultracold Atoms
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
path
Print the absolute path of the .bib file being operated on: the given BIBFILE, or the configured default_bib_file when BIBFILE is omitted. See path. With --json: a string.
$ bibdeskparser path
/Users/mg/Refs/refs.bib
config
Print the resolved configuration: the built-in defaults merged with whatever a discovered bibdeskparser.toml sets. Where config_path reports only the file in effect, config shows the effective value of every setting, including the ones the file omits. A BIBFILE only fixes the config-discovery directory (else the current directory; see Configuration); config needs no .bib file and never fails for a missing configuration file.
Options
--no-types– restrict the dump to the user-tunable settings, omitting the resolved entry-type/field data model (documented_types,recognized_entry_types,universal_fields,known_fields).--json– print the complete state as a JSON object, unset values asnull. The default output is TOML-shaped instead.
$ bibdeskparser config --no-types
verify_types = true
verify_fields = true
preprint_export = "unpublished"
protected_words = []
...
[preprint_archives]
arXiv = "https://arxiv.org/abs/{id}"
...
config_path
Print the absolute path of the bibdeskparser.toml configuration file in effect for the .bib file being operated on. Discovery checks the directory of the .bib file, then the file named by $BIBDESKPARSER_CONFIG, then the XDG location; first found wins (see Configuration). If no configuration file is found, the command fails with an error (the built-in defaults are then in effect). With --json: a string.
$ bibdeskparser config_path
/Users/mg/.config/bibdeskparser/bibdeskparser.toml
eval_format_spec KEY [FORMAT]
Print the citation key (or, with --filename, the file name) that a format-specifier pattern yields for the entry at KEY, via eval_format_spec(). Read only: nothing is renamed or moved. FORMAT defaults to the configured [auto_key] format ([auto_file] with --filename). A value already matching the format evaluates to itself, so any other output flags a nonconforming key or name.
Options
--filename FILE– evaluateFORMATas a file name instead, in the file-name dialect.FILEonly supplies the original-name specifiers%l/%L/%e/%E(e.g. its extension); it need not exist or be attached toKEY. Pass an empty string to select the dialect whenFORMATuses none of those.--json– print the result as a JSON string.
$ bibdeskparser eval_format_spec tests/Refs/refs.bib LapertPRA09 \
'%a1%c{journal}0%Y%u0'
LapertPRA2009
$ 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(). A preprint-only entry renders its preprint reference in the journal position, linked; any other entry’s eprint renders as a separate link after the journal reference.
Options
--format FORMAT– output format:markdown(default),tex, orhtml.--style STYLE– layout of multiple citations:default,paragraphs,numbered list, oritemized list.
$ bibdeskparser render tests/Refs/refs.bib GoerzA2023 --format tex
export [KEY...]
Export one or more entries as self-contained BibTeX text (including the definitions of any @string macros they reference), via export(). Each entry is reduced to the fields needed to typeset a bibliography, written as Unicode text, with @string references left bare. The output begins with a marker line recording the export options (see The plain format of exported files). Without --update, the command is read-only; with --update FILE, it rewrites the exported FILE in place.
Options
--no-unicode– export field values TeX-encoded, as written to the.bibfile, instead of as Unicode text.--expand-strings– replace@stringreferences by the macro’s value and emit no@stringdefinitions (by default they are prepended).--full– export every field except the date bookkeeping fields, with attachments and URLs as plain paths/URLs, instead of the minimal selection (--minimal, the default).--field FIELD– export only the named fields (repeatable and comma-separated). Mutually exclusive with--minimal/--full, and always exports the stored fields.--preprint FORM– the form a preprint-only entry is exported as, whatever its stored form:unpublished(structuredeprintfields, with the requirednoteguaranteed in minimal exports; the default, via thepreprint_exportsetting),misc(the same structured form),article(the pseudo-journal form, hyperlinked viaurl), orstored(no transformation).--outfile PATH– write to a file instead of stdout. Mutually exclusive with--update.--update FILE– rewrite the exported FILE (which must exist and be plain BibTeX, not a BibDesk database), refreshing it from the library: the given KEYs (without KEYs: every key in FILE that the library knows) take the library’s current values, KEYs not yet in FILE are appended, and everything else – unknown entries, comments,@stringdefinitions – is kept; nothing is ever removed. That holds field by field: a refreshed entry keeps the fields it has in FILE, in FILE’s own field order, and the field selection only adds to them. The--unicode/--expand-strings/--preprintoptions default to the FILE’s own recorded or detected options.--no-marker– do not begin the output with the marker line; with--update, leave the FILE’s marker state untouched.
$ bibdeskparser export tests/Refs/refs.bib GoerzA2023 \
--expand-strings --outfile out.bib
$ bibdeskparser export tests/Refs/refs.bib --update out.bib GoerzQ2022
Entries
rekey OLD_KEY [NEW_KEY]
Change the citation key of an entry from OLD_KEY to NEW_KEY, via rekey(). Without NEW_KEY, the key is generated from the configured auto-key format and printed; a key already matching the format is kept, and a %u/%U/%n specifier resolves collisions with other entries. To preview without renaming, use eval_format_spec.
Files named after the key follow the rename: the entry’s asset files are moved to the paths the new key resolves to, and attachments that follow the [auto_file] format are re-filed under the new key (a hand-named or missing file is skipped with a warning).
Options
--format-spec PATTERN– generate the new key from this format-specifier pattern instead of the configured one. Only valid withoutNEW_KEY.--no-rename-assets– do not move the entry’s asset files. Defaults to the[rekey]configuration (on).--no-rename-attachments– do not re-file the entry’s attachments. Defaults to the[rekey]configuration (on).
$ bibdeskparser rekey tests/Refs/refs.bib LapertPRA09 LapertPRA2009
$ bibdeskparser rekey tests/Refs/refs.bib LapertPRA09
LapertPRA2009
$ bibdeskparser rekey tests/Refs/refs.bib LapertPRA09 --format-spec '%a1:%Y%u0'
Lapert:2009
delete KEY...
Delete one or more entries from the library, via delete() (del lib[key]). The entries’ asset files and attachments stay on disk unless removal is switched on; files left behind are reported as warnings, and removed files go to the Trash where possible.
Options
--remove-assets– also delete each entry’s asset files from disk. Defaults to the[delete]configuration (off).--remove-attachments– also delete each entry’s attached files from disk (a file still linked from another entry is kept). Defaults to the[delete]configuration (off).
$ 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. Like BibDesk, a VALUE that is a valid @string macro name is stored as a bare macro reference. The keywords, date, and bdsk-* fields cannot be set this way (use add_to_keyword, add_file, add_url); an author/editor VALUE must parse as names.
Options
--literal– storeVALUEas literal text (ValueString), even if it is a valid macro name.--macro– storeVALUEas a bare macro reference (MacroString), failing if it is not a valid macro name.
$ bibdeskparser set_field tests/Refs/refs.bib TuriniciHAL00640217 note \
"Lecture notes for a graduate course"
An empty VALUE is an error, since BibDesk deletes empty fields on save (see Empty fields): use delete_field to remove a field, or add the entry to a known-missing group to record a verified absence.
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
Import the entries of a BibTeX snippet into the library and print their citation keys, via import_bibtex(). The snippet may be anything from a single publisher-provided entry to a complete .bib file (including @string definitions). Every entry is sanitized on the way in (see the method for the full list): the journal becomes an @string macro reference, title proper nouns are brace-protected, the DOI is normalized, and, for articles, a page range collapses to its first page and non-essential fields are dropped. A preprint-only entry (a pseudo-journal like arXiv:2205.15044, or a misc/unpublished entry with an eprint) is normalized to an @unpublished entry with the canonical pseudo-journal and derived eprint/archiveprefix/doi fields; an unrecognized archive prefix is an error unless --keep-journals is given. Citation keys are regenerated. An entry whose DOI or eprint is already in the library is rejected, and any problem rejects the whole import, reporting everything at once with the .bib file untouched.
Options
--file FILE– read the snippet from FILE.--stdin– read the snippet from standard input.--url URL– download the snippet from URL. Give exactly one of--file,--stdin, or--url.--keep-keys– keep the incoming citation keys instead of regenerating them.--keep-journals– preserve each journal as-is instead of converting it to an@stringmacro reference.--fix-uppercase– repair all-uppercase names and titles found in some publisher data.
$ bibdeskparser import tests/Refs/refs.bib --file 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
A positional argument ending in .bib always names the library, like every other command; give the import source with --file (so --file is required even with a configured default_bib_file).
add QUERY...
Fetch bibliographic data for QUERY from the appropriate online source and add it as a new, sanitized entry (the same sanitization as import), via add(), printing its citation key. All QUERY arguments join into one query:
an arXiv identifier (
2205.15044,quant-ph/0106057), or any string containing one (e.g. anarxiv.orgURL), is fetched from the arXiv API and added as a preprint-only@unpublishedentry;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, so verify the result.
Requires network access; the arXiv API’s rate limits are respected automatically.
Options
--dry-run– print the fetched entry (as re-parseable BibTeX) without modifying the.bibfile.--fix-uppercase– repair all-uppercase names and titles in the fetched metadata.--add-abstract– also store the abstract returned alongside the metadata (seeadd_abstract).--add-preprint– also search arXiv for a matching preprint (seeadd_preprint), reporting to stderr; skipped when the entry already has aneprint.
The --fix-uppercase and --add-* options default to the [add] configuration, each with a negative form (--no-add-abstract, …) to override a configured true.
$ 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
$ bibdeskparser add tests/Refs/refs.bib --dry-run 10.22331/q-2022-01-24-629
@string{quant = {Quantum}}
@article{SilverioQ2022,
...
Abstracts, preprints, and DOIs
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 doi), the first attached PDF’s text (needs poppler’s pdftotext on PATH), the arXiv API (via eprint), and Semantic Scholar; each is cleaned to plain-unicode prose, and the best is stored in the abstract field if its confidence reaches --min-confidence:
high: an online abstract identified bydoi/eprint, or an unambiguous PDF extraction;medium: a single unconfirmed source;low: the PDF text and an online source disagree.
An entry that already has an abstract is skipped (see --overwrite). A candidate that was not stored is reported in full, to review and apply with set_field. With a known-missing group configured for abstract, a clean search that finds nothing adds the entry to the group and later runs skip it, while storing an abstract removes it; a search in which any source failed never marks the entry. Requires network access.
Options
--min-confidence LEVEL– lowest confidence stored automatically:high(default),medium, orlow. Defaults to the[add_abstract]configuration.--overwrite– refetch and replace an existing abstract, and re-search the known-missing group members.--dry-run– print the report without modifying the.bibfile (it then sayswould store).--json– map each key to{abstract, source, confidence, note, applied}.
$ bibdeskparser keys tests/Refs/refs.bib --type article --missing abstract
SauvagePRXQ2020
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), and, on a confident match, its identifier is stored in the eprint field, along with archiveprefix and the primary category (e.g. quant-ph) as primaryclass. A result is accepted only when
its arXiv DOI equals the entry’s
doi, orits title is a near-exact match, or
a good title match is corroborated by the first author’s last name.
A match postdating the entry’s year by more than a year is only reported unless its journal reference names that year; apply such a candidate with --eprint. An entry that already has an eprint is skipped (see --overwrite). With a known-missing group configured for eprint, a clean search that finds no preprint adds the entry to the group and later runs skip it, while storing an identifier removes it; a failed search never marks the entry. Membership means “searched, none found at the time”, so re-audit the group members periodically with --overwrite. 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.
Options
--eprint ID– store this arXiv identifier explicitly instead of searching (a singleKEYonly, no network access; a leadingarXiv:prefix and a version suffix are stripped).--overwrite– replace an existingeprint, and re-search the known-missing group members.--dry-run– print the report without modifying the.bibfile (it then sayswould store).--json– map each key to{eprint, match, ratio, note, applied, primaryclass}.
Re-audit the known-missing group members like this:
$ bibdeskparser add_preprint tests/Refs/refs.bib --overwrite \
$(bibdeskparser keys tests/Refs/refs.bib --group "No Eprint")
$ bibdeskparser keys tests/Refs/refs.bib --type article --missing eprint
WinckelIP2008
$ bibdeskparser add_preprint tests/Refs/refs.bib \
WinckelIP2008 Vecheck2022.09.09.507322
WinckelIP2008: no preprint found (marked known missing in group 'No Eprint') [best-ratio=0.42]
Vecheck2022.09.09.507322: no preprint found (marked known missing in group 'No Eprint') [best-ratio=0.31]
The report above assumes a known-missing group declared for eprint in bibdeskparser.toml; without one, the two lines end at the [best-ratio=...] note and nothing is recorded.
add_doi KEY...
Find and store the DOI for the given entries, via add_doi(). For each KEY, the DOI is looked up online: via the arXiv API if the entry has an eprint (the recorded DOI names the published version of this paper), else via a Crossref search by title and first author, accepted only when
its title is a near-exact match, or
a good title match is corroborated by the first author’s last name.
A match whose year differs from the entry’s year by more than one is only reported; apply it with --doi. An amendment (erratum, corrigendum, retraction, comment, reply) never matches a non-amendment entry. The DOI is stored in bare lowercase form. An entry that already has a doi is skipped (see --overwrite), as is a preprint-only entry (its published version’s DOI does not belong on a preprint reference; store it with --doi). With a known-missing group configured for doi, a clean lookup that finds nothing adds the entry to the group and later runs skip it, while storing a DOI removes it; a failed lookup never marks the entry, and membership also lets check accept an article without a doi. Requires network access (except with --doi); an eprint lookup respects arXiv’s rate limit of one request every three seconds.
Options
--doi DOI– store this DOI explicitly instead of searching (a singleKEYonly, no network access; a leadingdoi:prefix orhttps://doi.org/resolver address is stripped).--overwrite– replace an existingdoi, and re-search the known-missing group members.--dry-run– print the report without modifying the.bibfile (it then sayswould store).--json– map each key to{doi, match, ratio, note, applied}.
Re-audit the known-missing group members like this:
$ bibdeskparser add_doi tests/Refs/refs.bib --overwrite \
$(bibdeskparser keys tests/Refs/refs.bib --group "No DOI")
$ bibdeskparser add_doi tests/Refs/refs.bib GoerzPhd2015 GoerzDiploma2010
GoerzPhd2015: no doi found (marked known missing in group 'No DOI') [best-ratio=0.55]
GoerzDiploma2010: no doi found (marked known missing in group 'No DOI') [best-ratio=0.47]
The report above assumes a known-missing group declared for doi in bibdeskparser.toml; without one, the two lines end at the [best-ratio=...] note and nothing is recorded.
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 Diploma
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
Document info
set_info KEY VALUE
Create or update the document-info key KEY (see info) as VALUE. KEY is matched case-insensitively against the existing keys; a new key must be a valid BibTeX field name. Corresponds to lib.info[key] = value (see info).
$ bibdeskparser set_info tests/Refs/refs.bib project qdyn
delete_info KEY
Remove the document-info key KEY (matched case-insensitively). Removing the last key removes the @bibdesk_info block from the .bib file. Corresponds to del lib.info[key].
$ bibdeskparser delete_info tests/Refs/refs.bib primary_topics
Files
The commands in this section modify an entry’s file attachments; the read-only files command lists them.
add_file KEY FILENAME
Attach the file FILENAME to the entry KEY, via add_file(). When auto-filing is in effect, the file is moved into the auto-file location, renamed by a file-name format, and its stored path (relative to the .bib file) is printed. Auto-filing is in effect when --location or --format-spec is given, or when the configuration sets file_automatically = true.
Options
--no-check-exists– do not requireFILENAMEto exist on disk (incompatible with auto-filing).--location DIR– auto-file into DIR (relative to the.bibfile, or absolute) instead of the configured location.--format-spec PATTERN– auto-file using this file-name format instead of the configured one.--no-auto-file– attach under the original name even when the configuration enables auto-filing.
$ bibdeskparser add_file tests/Refs/refs.bib Shapiro2012 papers/shapiro-brumer.pdf
$ 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().
Options
--remove– also delete the old file from the filesystem.--no-check-exists– do not requireNEWto exist on disk.
$ bibdeskparser replace_file tests/Refs/refs.bib GoerzJPB2011 \
GoerzJPB2011.pdf corrected.pdf --remove
unlink_file KEY FILENAME
Remove FILENAME from the entry’s attachments, via unlink_file(). Pass --remove to also delete the file from the filesystem.
$ bibdeskparser unlink_file tests/Refs/refs.bib GoerzQ2022 GoerzQ2022.pdf
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(). Without NEW, the target is generated by auto-filing: the file is moved into the auto-file location and renamed by the configured file-name format, and the new path (relative to the .bib file) is printed. A file already matching the format is left in place, and a %u/%U/%n specifier resolves collisions with existing files. To preview without moving anything, use eval_format_spec --filename.
Options
--format-spec PATTERN– generate the new name from this file-name format instead of the configured one. Only valid withoutNEW.--location DIR– move the file into DIR (relative to the.bibfile, or absolute) instead of the configured auto-file location. Only valid withoutNEW.
$ bibdeskparser rename_file tests/Refs/refs.bib MorzhinRMS2019 \
MorzhinRMS2019.pdf Reviews/MorzhinRMS2019.pdf
$ bibdeskparser rename_file tests/Refs/refs.bib GraceJMO2007 grace_jmo_2007.pdf
GraceJMO2007.pdf
URLs
The commands in this section modify an entry’s linked URLs; the read-only urls command lists them.
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 TomzaPRA2012 \
http://dx.doi.org/10.1103/PhysRevA.86.043424
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 ever blocks without a terminal: with no TTY on stdin and neither --stdin nor --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 text to edit is exactly what export prints for the same keys.
Options
--editor CMD– editor command to use (default:$EDITOR).--stdin– read the full edited text from standard input instead of opening an editor (mutually exclusive with--editor). Empty input is a usage error; input that fails validation exits 1 with the.bibfile untouched.
$ bibdeskparser edit tests/Refs/refs.bib GoerzQ2022 --editor vim
$ bibdeskparser export tests/Refs/refs.bib GoerzQ2022 \
| sed 's/Semi-Automatic/Semiautomatic/' \
| bibdeskparser edit tests/Refs/refs.bib GoerzQ2022 --stdin
edit_strings
Edit the @string macro definitions and merge the changes back into the library, via edit_strings(). The baseline text comes from strings --bib.
Options
--editor CMD– editor command to use (default:$EDITOR).--stdin– read the full edited definitions from standard input instead of opening an editor (mutually exclusive with--editor).
$ bibdeskparser edit_strings tests/Refs/refs.bib
$ bibdeskparser strings tests/Refs/refs.bib --bib \
| sed 's/EPJ Quantum Technol./EPJ Quantum Technology/' \
| bibdeskparser edit_strings tests/Refs/refs.bib --stdin