Merging bib files from within LaTeX

I have two .bib files that I want to use in my bibliography. Entries do not overlap. I have found quite a few forum topics on that, but none of them really satisfied me. So my idea is to merge the two to one .bib file which I will use in the .tex. Most conveniently, this would be done from within LaTeX (so I do not use bibtool, or reference software). So, I made a macro to merge two files:

\newwrite\bibwrite
\newcommand{\concatbib}[2]{%
\begingroup
\IfFileExists{#1}%
{\CatchFileDef{\bibone}{#1}{}}
{\let\bibone\empty}
\IfFileExists{#2}%
{\CatchFileDef{\bibtwo}{#2}{}}
{\let\bibtwo\empty}%
\immediate\openout\bibwrite=MyBib.bib\relax
\immediate\write\bibwrite{\bibone \bibtwo}%
\immediate\closeout\bibwrite
\endgroup
}


which is basically taken from another question (How can I open a file in "append" mode?). Now the problem is that Latex wants to interpret the file contents, and things like \noexpand, \detokenizedid not work as desired. So I have to read it in verbatim, which I tried according to Martin Scharrer's answer here: Control command arguments.

\def\alltext{
\begingroup
\let\do\@makeother % define \do to change the category code of its argument to 'other'
\dospecials % makro that is a string of every special character preceeded with \do -> all catcodes are changed
\all@text
}
\def\all@text#1{
\endgroup
#1
}


and I would use this within the other macro. Testing it alone, though, I get the error that Use of \all does not match its definition \alltext, and I think that I am missing a big point here.

• I think that I put the definition of \all@text after \alltext so I can close the group, which to my understanding I need to define the region where the catcodes are altered. But I do not see why \all@text should be known already in the definition of \alltext?
• up to now I understood that \@... commands are primitive commands, but I thought it was only a notation. Is there more to it?
• is there a way to make that code work?
• This is easier than cat? – jon Apr 3 '13 at 17:59
• Do you even need to combine the two files? If they're named, say, biblio1.bib and biblio2.bib, BibTeX and LaTeX can access both files easily via the statement \bibliography{biblio1,biblio2}. – Mico Apr 3 '13 at 18:09
• @Mico I guess you should make that the answer. – David Carlisle Apr 3 '13 at 19:05
• @DavidCarlisle - Done! :-) – Mico Apr 3 '13 at 19:41
• Why don't you merge them with jabref? – user11232 Apr 3 '13 at 22:48

I'm not sure if I'm missing something about your setup, but do you even need to combine the two .bib files? If they're named, say, biblio1.bib and biblio2.bib, BibTeX and LaTeX can access both files easily via the statement

\bibliography{biblio1,biblio2}


If you employ the biblatex package, I understand that the preferred style is to use a pair of separate \addbibresource statements (cf. section 3.6.1 of the package's manual):

\addbibresource{biblio1.bib}


Observe that it's necessary to provide the filename extension .bib when using the \addbibresource command, whereas one should not provide this extension when using the \bibliography command.

• Thanks a lot, I was not aware of that - sometimes life is easier than you'd think :-) – Heinrich Apr 4 '13 at 8:23

If you really want to do it at the TeX level (which is not really required because you can input as many .bib file as you want), here's a set of macro doing it. You can give as mandatory argument to \concatbib any number of bib file names (without extension), separated by commas.

\documentclass{article}

\usepackage{xparse}

\ExplSyntaxOn
% The document level command
\NewDocumentCommand{\concatbib}{ O{output} m }
{
\heinrich_concatbib:nn { #1 } { #2 }
}

% Variables and messages
\ior_new:N \l__heinrich_input_stream
\iow_new:N \l__heinrich_output_stream
\msg_new:nnnn { concatbib } { file-exist }
{ File~#1'~exists.~Not~overwriting.}

% Internal functions
% First we check that the named output file doesn't exist
\cs_new_protected:Npn \heinrich_concatbib:nn #1 #2
{
\file_if_exist:nTF { #1.bib }
{
\msg_error:nnn { concatbib } { file-exist } { #1.bib }
}
{
\__heinrich_concatbib_aux:nn { #1 } { #2 }
}
}
% If we're writing, we open an output stream and cycle
% through the second argument, a comma separated list
% of bib file names
\cs_new_protected:Npn \__heinrich_concatbib_aux:nn #1 #2
{
\iow_open:Nn \l__heinrich_output_stream { #1.bib }
\clist_map_inline:nn { #2 } { \__heinrich_read_write:n { ##1 } }
\iow_close:N \l__heinrich_output_stream
}
% At each step we read each line of the current .bib file
% and write it to the output stream
{
\ior_open:Nn \l__heinrich_input_stream { #1.bib }
\ior_str_map_inline:Nn \l__heinrich_input_stream
{ \iow_now:Nn \l__heinrich_output_stream { ##1 } }
\ior_close:N \l__heinrich_input_stream
}
\ExplSyntaxOff

% This will concatenate in output.bib'
\concatbib{foo1,foo2}

% This will concatenate in foo.bib'
\concatbib[foo]{foo1,foo2}

• wow - do you have a suggestion for a good introduction to this? (what do the :n s mean; the ##1 is new to me as well) – Heinrich Apr 4 '13 at 8:39
• @Heinrich Do texdoc xparse and texdoc interface3 – egreg Apr 4 '13 at 10:41

Hm... I am a big friend of use-the-right-tool-for-the-task. So while intellectually enlightening, I would not go to implement this in LaTeX, but just use the basic OS capabilities (no bibtool or other fancy stuff required):

On Linux/UNIX/MacOS, open a bash (or whatever shell or terminal) in the respective directory and enter:

cat bibone.bib bibtwo.bib >MyBib.bib


On Windows, open a CMD prompt and enter:

type bibone.bib bibtwo.bib >MyBib.bib


On both systems you can also append to an existing MyBib.bib by redirecting the output with >> instead of >.