7

I am using the animate package and have the pdf files to animate in a separate folder. I need to input the number for the first and last file, but am occasionally changing the number of files I would like to animate. Is there any way to have LaTex automatically count the number of files in the folder?

Here is some example code that hopefully better explains what I am after

\documentclass{article}
\usepackage{animate}
%
\begin{document}
\animategraphics[controls]{1}{./pdfFolder/fileName_}{1}{numFiles}
\end{document} 

I would like LaTex to automatically update "numFiles" depending on the number of files in "pdfFolder".

Thank you in advance for your help!

3 Answers3

11

Pure LaTeX: (fileName_1.pdf ... fileName_?.pdf)

\documentclass{article}
\usepackage{animate}
\usepackage{graphicx}

\newcounter{NumFiles}
%\setcounter{NumFiles}{-1} % fileName_0.pdf ... fileName_?.pdf

\newboolean{stop}
\whiledo{\NOT\boolean{stop}}{
  \stepcounter{NumFiles}
  \IfFileExists{./pdfFolder/fileName_\theNumFiles.pdf}{}{
    \addtocounter{NumFiles}{-1}
    \setboolean{stop}{true}
  }
}

\begin{document}
  \animategraphics[controls]{1}{./pdfFolder/fileName_}{1}{\theNumFiles}
\end{document}
AlexG
  • 54,894
  • Why not have \stepcounter{NumFiles} inside the if-statement? If-true, count up, if-false, stop counting (rather than decrementing the extra unconditional count). – Atcold Feb 22 '23 at 20:24
  • Did you run a test? It would lead to the same problem of one count-up too much, which would have to be undone in the false branch upon the last iteration. – AlexG Feb 22 '23 at 20:39
  • I did try running it and the output was zero, so, I'm not entirely sure what was going on… Also, I'm not sure I understand why that would lead to an extra count-up since we would have an if-false condition. Moreover, I've tried packaging it in a macro and return \theNumFiles. I'm having issues in assigning the returned value to a variable, say \edef\N{\countFiles{my_path}}. – Atcold Feb 22 '23 at 20:51
  • 1
    (1) I tested your approach and it is obvious: If fileName_5 is the highest-numbered existing file, then \IfFileExists enters the "true" branch and NumFiles gets one extra increment. There is one more iteration to follow which tests the non-existing fileName_6. Hence, it is necessary to decrement NumFiles in the "false" branch in order to obtain the correct count. – AlexG Feb 22 '23 at 22:14
  • (2) This will not work, because \countFiles{my_path} is not expandable and cannot be used in an \edef. (Any macro that makes assignments or definitions under the hood is not expandable.) You can work around this by passing \N as a second argument to your macro. Your macro then sets \N in its body. – AlexG Feb 22 '23 at 22:22
  • (1) Oh my, I'm dumb… (2) I don't understand why \countFiles{my_path} is not expandable. Any ref? Also, to pass \N I have to \def it. How is it that I can set it in the macro body? This is new territory for me… Thanks again for engaging. – Atcold Feb 23 '23 at 16:36
  • 1
    Expansion and TeX is a long story. Maybe this is of some help. In short: If your macro \countFiles performs assignments (e. g. \stepcounter, \setboolean) then it is not expandable anymore, and thus cannot be used in the definition body of an \edef. Define your macro as \def\countFiles#1#2{... \edef#1{\theNumFiles}} and call it like so: \countFiles\N{my_path}. You don't need to define \N beforehand. – AlexG Feb 23 '23 at 17:00
  • I did it and it worked. Thanks a bunch! I had no idea I could use \N before defining it. I guess it's used as an arbitrary token and it would lead to an error only if expanded. I wish there was a TeX programming primer to read. – Atcold Feb 24 '23 at 20:23
5

Here is an approach with basic Unix commands and \write18{}, listing the contents first and using the wc -l command, saving the output into dummyvar.tex and reading that file to the \numFiles macro.

Of course, the shell-script should be much more failsafe, i.e. store it in a separate file, say countmyfiles.sh and source that file within \write18{source countmyfiles.sh} rather.

\documentclass{article}

\usepackage{animate}


\def\numFiles{-1}

\newread\numfileshandle
\begin{document}
\write18{rm -f dummyvar.tex ; ls -l pdfFolder/fileName_* | wc -l > ./dummyvar.tex}
\immediate\openin\numfileshandle=dummyvar.tex
\read\numfileshandle to \numFiles
\immediate\closein\numfileshandle

There are \numFiles Files

%\animategraphics[controls]{1}{./pdfFolder/fileName_}{1}{\numFiles}
\end{document} 

A test with 20 dummy files within my dummy folder pdfFolder yields 20 as output.

  • Don’t forget that you can avoid using a temporary file by having recourse to the “piped input” feature: see, for example, this, this, and this answer of mine. (Sorry for quoting my own answers, but it’s simply the easiest thing for me, since I don’t have to study someone else’s code… ;-) – GuM Mar 01 '17 at 23:16
1

Christian has declined my suggestion about using the piped input feature, but I still think it may be interesting to show how it could be used in this case. Note how the argument of the \countfiles macro is pre-processed in order to permit the use of “special” characters, like _ and balanced occurences of { and }, while, at the same time, allowing macros (or, more generally, expandable control sequences) to be expanded, as it is shown below for \myDirName and \jobname.

% My standard header for TeX.SX answers:
\documentclass[a4paper]{article} % To avoid confusion, let us explicitly 
                                 % declare the paper format.

\usepackage[T1]{fontenc}         % Not always necessary, but recommended.
% End of standard header.  What follows pertains to the problem at hand.

\newcounter{numberOfFiles}

\makeatletter

% Beware: "special" characters like "_" that appear in the directory name must
% be either re-"\catcode"d or "\detokenize"d: the latter method is **much**
% simpler than the former, but it does **not** cope with filenames containing
% the "%" character, or unbalanced "{" and "}" characters, and in addition it
% requires e-TeX extensions (not at all a concern, these days!).
\newcommand*{\countfiles}[1]{%
    \begingroup
        \protected@edef\@tempa{#1}% before detokenizing, expand expandable (and 
                                  % unprotected) tokens
        % We use "\@inputcheck" for the temporary input pipe:
        \openin\@inputcheck "|ls -1 % the last character is the digit "one"
                \expandafter\detokenize\expandafter{\@tempa} % space meant
                |wc -l% the last character is the letter "ell"
                "\relax % without the "\relax", the ensuing "\ifeof" would be 
                        % prematurely expanded
        \ifeof\@inputcheck
            % An error message could be triggered here.
            \typeout{WARNING: Could not read \protect\numFiles!}%
        \else
            \endlinechar \m@ne % cf. exercise 20.18
            \readline\@inputcheck to\@tempa
            \setcounter{numberOfFiles}{\@tempa}%
        \fi
        \closein\@inputcheck % note: no "\immediate" needed for "\closein"
    \endgroup
}

\makeatother

\newcommand*{\myDirName}{some_directory}



\begin{document}

\setcounter{numberOfFiles}{-1}\countfiles{\myDirName}
There are \arabic{numberOfFiles} files in the specified directory.

\bigbreak

\setcounter{numberOfFiles}{-1}
In the current directory there are:
\begin{tabbing}
    \quad 999\=\kill
    \countfiles{\jobname.*}\>\arabic{numberOfFiles}\'
            file(s) whose basename is \texttt{\jobname};\\
    \countfiles{*.{tex,log}}\>\arabic{numberOfFiles}\'
            file(s) whose extension is either \texttt{.tex} or \texttt{.log};\\
    \countfiles{[A-Za-z]*.tex}\>\arabic{numberOfFiles}\'
            file(s) whose name consists only of letters, followed by the 
            extension \texttt{.tex}.
\end{tabbing}
That's all, folks!

\end{document}
GuM
  • 21,558