3

I have a latex document containing some problems and their solutions. I also have a macro \excludecomment{sol} which if uncommented, excludes the solution environments. (Similar command is there for prob environment.)

The general question is whether I can include a command in these macros or otherwise so that depending on whether the macro is active or not is reflected in the filename of the PDF file (e.g., by adding a _sol to the filename when the solutions are present.)

1
5

You can't change the name of the output files/the name of the .pdf file **during* the TeX run/LaTeX run.

The reason is:

The output files are created anew and opened for writing right at the beginning of the TeX run/LaTeX run.
(E.g., the .log file is created anew and opened for writing right after starting the tex-executable or latex-executable. E.g., the .pdf file is created anew and opened for writing when shipping out the very first page of the document. )
The output files (and thus also the .pdf file) are left open for writing until the end of the TeX run/LaTeX run.
With most computer platforms you can't change the name of a file while that file is open for writing.

But with most TeX-platforms you can run tex-binaries/executbales with command line options.

One of these options is the option -jobname.

If you have the main .tex-file foo.tex and compile it by running latex from the command line as

pdflatex --jobname=bar foo.tex

, you won't get the output files foo.aux, foo.log and foo.pdf, etc, but you will get output files bar.aux, bar.log and bar.pdf, etc.

Also the primitive \jobname won't deliver the phrase foo in this case but will deliver the phrase bar.

You can't use a macro for changing the names of output files during the LaTeX run but you can go the other direction:

Create a macro which examines whether the expansion of \jobname contains some specific phrase and forks accordingly. Be aware that \jobname spits out explicit space tokens of category code 10(space) and explicit character tokens of category code 12(other).


Example:

Save the following example as test.tex :

\documentclass{article}
\usepackage{comment}

\begingroup    
\makeatletter
%%----------------------------------------------------------------------
%% Check whether argument is empty:
%%......................................................................
%% \UD@CheckWhetherNull{<Argument which is to be checked>}%
%%                     {<Tokens to be delivered in case that argument
%%                       which is to be checked is empty>}%
%%                     {<Tokens to be delivered in case that argument
%%                       which is to be checked is not empty>}%
%% The gist of this macro comes from Robert R. Schneck's \ifempty-macro:
%% <https://groups.google.com/forum/#!original/comp.text.tex/kuOEIQIrElc/lUg37FmhA74J>
\long\def\UD@CheckWhetherNull#1{%
  \romannumeral0\expandafter\@secondoftwo\string{\expandafter
  \@secondoftwo\expandafter{\expandafter{\string#1}\expandafter
  \@secondoftwo\string}\expandafter\@firstoftwo\expandafter{\expandafter
  \@secondoftwo\string}\expandafter\expandafter\@firstoftwo{ }{}%
  \@secondoftwo}{\expandafter\expandafter\@firstoftwo{ }{}\@firstoftwo}%
}%
%%----------------------------------------------------------------------
%% Check whether expansion of \jobname contains no phase "_sol"
%%......................................................................
%% \UD@CheckWhetherNoSolInJobname{<Tokens to be delivered in case that
%%                                 \jobname contains no phrase "_sol">}%
%%                               {<Tokens to be delivered in case that
%%                                 \jobname contains the phrsae "_sol">}%
\def\UD@GobbleToSol{_sol}%
\@onelevel@sanitize\UD@GobbleToSol
\edef\CheckWhetherNoSolInJobname{%
  \noexpand\expandafter\noexpand\UD@CheckWhetherNull
  \noexpand\expandafter{\noexpand\UD@GobbleToSol\jobname\UD@GobbleToSol}%
}%
\expandafter\long\expandafter\def
\expandafter\UD@GobbleToSol\expandafter#\expandafter1\UD@GobbleToSol{}%
\CheckWhetherNoSolInJobname{%
  \endgroup
  \newcommand\CheckWhetherNoSolInJobname[2]{#1}%
}{%
  \endgroup
  \newcommand\CheckWhetherNoSolInJobname[2]{#2}%
}%
%% \makeatother not needed. Instead the group is closed.
%%----------------------------------------------------------------------

\CheckWhetherNoSolInJobname{%
  \excludecomment{sol}%
}{%
  \includecomment{sol}%
}%

\begin{document}

Expansion of \verb|\jobname| is: \texttt{\jobname}

\texttt{\string\jobname} does
\CheckWhetherNoSolInJobname{%
  not%
}{%
  indeed%
}
contain the phrase \verb|_sol|.

Thus solutions
\CheckWhetherNoSolInJobname{%
  are not included%
}{%
  get included also%
}.

\bigskip

This is the question.
\begin{sol}

This is the answer.
\end{sol}

\end{document}

Compiling from the command line via pdflatex test.tex yields test.pdf which looks like this:

enter image description here

Compiling from the command line via pdflatex --jobname=test_sol test.tex yields test_sol.pdf which looks like this:

enter image description here



Another approach could be:

File test_sol.tex:

\newcommand\solutioninorexclude{%
  \includecomment{sol}%
}%
\input test.tex

File test.tex:

\documentclass{article}
\usepackage{comment}
\providecommand\solutioninorexclude{%
  \excludecomment{sol}%
}%
\solutioninorexclude    

\begin{document}

This is the question.
\begin{sol}

This is the answer.
\end{sol}

\end{document}

Compiling test_sol.tex yields test_sol.pdf:

enter image description here

Compiling test.tex yields test.pdf:

enter image description here

A variation on this approach can be having test.tex create the file test_sol.tex for you automatically in case it does not exist:

When you save the example below as test.tex and compile it, you will get a file test.pdf which contains the text without solutions. You also get a file test_sol.tex. If you compile that, it will—via \input—import test.tex in a way where sol-environments are included. Thus you get a file test_sol.pdf which does also contain solutions:

\documentclass{article}
\usepackage{comment}
\providecommand\solutioninorexclude{%
  \excludecomment{sol}%
  \includecomment{solinputfile}%
}%
\solutioninorexclude    

\begin{solinputfile}
\begingroup
\makeatletter
\IfFileExists{\jobname\string_sol.tex}{%
  \@latex@warning@no@line{File \jobname\string_sol.tex already exists. Not generating it}%
}{%
  \@latex@warning@no@line{Generating file \jobname\string_sol.tex}%
  \newwrite\solinputfile
  \immediate\openout\solinputfile\jobname\string_sol.tex\relax
  \immediate\write\solinputfile{%
    \string\newcommand\string\solutioninorexclude{\@percentchar^^J%
    \space\space\string\includecomment{sol}\@percentchar^^J%
    \space\space\string\excludecomment{solinputfile}\@percentchar^^J%
    }\@percentchar^^J%
    \string\input\space\jobname.tex%
  }%
  \immediate\closeout\solinputfile
}%
\endgroup
\end{solinputfile}

\begin{document}

This is the question.
\begin{sol}

This is the answer.
\end{sol}

\end{document}


Yet another approach could be using something like the docstrip package. The purpose of the docstrip package is copying files of tex-source-code with having comments removed. It provides means for conditional inclusion of code into the copies.

E.g. if you save the following example as test.tex and compile it, you don't get a .pdf file but you get two new text files.

%<*ignore>
\input docstrip
\nopreamble
\nopostamble
\askforoverwritetrue
\generate{\file{\jobname\string_sol.tex}{\from{\jobname.tex}{sol}}}
\generate{\file{\jobname\string_nosol.tex}{\from{\jobname.tex}{}}}
% Here you can do some \immediate\write18-calls for calling LaTeX or
% TeXify or latexmk for compiling \jobname_sol.tex and
%\jobname_nosol.tex.
% You need to have the \write18-feature enabled for this.
% Some people take enabling \write18 for a security issue.
\csname stop\endcsname
\bye
%</ignore>
\documentclass{article}
% This comment won't occur in the generated files.
% This comment won't occur in the generated files.
\begin{document}
This is the question.
%<*sol>

This is the answer.
%</sol>
\end{document}

One of these text files is named test_nosol.tex and its content is:

\documentclass{article}
\begin{document}
This is the question.
\end{document}

The other of these text files is named test_sol.tex and its content is:

\documentclass{article}
\begin{document}
This is the question.

This is the answer.
\end{document}
5
  • -jobname is TeX option, no LaTeX option. – wipet May 11 '20 at 10:17
  • @wipet With every latex-binary I used in the last two decades, the commandline-option -jobname was available. For example, when on debian in bash I type latex --help, I get: ...-jobname=STRING set the job name to STRING... And that help-text is correct: In bash you can do latex --jobname=foo bar.tex for compiling the latex-document bar.tex to foo.pdf. – Ulrich Diez May 11 '20 at 14:39
  • If I do ln -s /usr/local/texlive/2020/bin/x86_64-linux/tex bobo then I can do bobo --help or bobo --jobname=foo bar.tex. Everything works (the second example only if bobo.fmt format is present). But there is no bobo-binary, only TeX binary. The "latex binary" is equivalent with "bobo binary" in this example. – wipet May 11 '20 at 15:42
  • @wipet Maybe its symbolic link in texlive. E.g., in MiKTeX 2.4 under Win95 and in MiKTeX 2.9 under Win7 each format has its own binary/executable. – Ulrich Diez May 11 '20 at 16:32
  • OK, you are right. Nice day. – wipet May 11 '20 at 18:23
1

I've been dealing with the same situation for years and I just came with the following solution today after browsing TeX.stackexchange. It does not strictly answer your question but I find it easy to use as a workaround solution. I use the exam package but this should work for any package where you have the option to comment out some portions using a macro. For the exam package, the code that is optionnally included is in the solution environment. I created three files with the following scheme (but shorter names in practice):

1) main_questions_only.tex whose entire content is

\documentclass[11pt]{exam}
\noprintanswers
\input{main.tex}

2) main_questions_with_solutions.tex whose entire content is

\documentclass[11pt]{exam}
\printanswers
\input{main.tex}

3) main.tex contains everything else.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.