6

I have several .txt or .dat files, whose names are of the form: dn-ddmmyyyy.txt. For instance:

d0-01021989.txt
d1-21021989.txt
d2-15021994.txt
d3-12121996.txt
d4-14032014.txt
d5-22022035.txt
...many more...

What is the best way to include all the files without using manually \include for each one of them?

Is there a way to create a title (like a chapter title) for each document, as "Document N", and extract the number present in the file name, which is a date, to put it in the title?

Is there a way to do this only with TeX?

  • 1
    Honestly, my first thought is some sort of shell script. I don't see any pattern that would allow TeX to predict the filename. (I mean, you could have TeX count until it reaches a present file for each dN, but that would be terribly slow.) How are the filenames generated, if they're generated? – Sean Allred Sep 13 '14 at 3:20
  • Which operating system do you use: Windows, MacOSX, something else? And what's the preferred sorting order: by the numer after "d", by the date string, or randomly chosen? Please advise. – Mico Sep 13 '14 at 6:01
  • @SeanAllred The filenames was generated manually. – OSjerick Sep 13 '14 at 13:07
  • @Mico I'm using Linux and Windows, I mean, I can compile the document through a Dropbox directory, it would be cool if I could do it without problems on both operating systems. The preferred order is by the date. – OSjerick Sep 13 '14 at 13:19
  • Wouldn't yyyymmdd be better since that would at least order your files sensibly? – Seamus Sep 15 '14 at 10:59
8

I don't know about a TeX only solution (I could however imagine that lualatex could by handy) but what I usually do is the following:

1) use a command like dir /b *.tex > allFiles.txt? to get a file of all the TeX files. (the /b suppresses everything but the file name)

2) open up Excel, paste the content of allFiles.txt and use string concatenation to build the include commands.

For once-only this is the most efficient solution. In cases where I regularly have to update my TeX file I'd write a short Python/Bash/Batch file.

EDIT:

I have found some suitable code to include via lualatex Lua-calls in one of the answers here and was able to adjust it a little. It uses \write18 as well, so it must be used with --shell-escape. I am pretty sure that a Lua-only solution is possible, but this is clearly beyond my Lua-knowledge.

%!TEX TS-program = LuaLaTeX

\documentclass[12pt,ngerman]{scrartcl}
\usepackage{luacode}

\begin{document}
Some text before the Lua call.

\begin{luacode}
function scandir(directory)
    local i, t, popen = 0, {}, io.popen
    for filename in popen('dir "'.. directory .. '" /b d*.tex'):lines() do
        i = i + 1
        t[i] = filename
       tex.print('\\input{includes/' .. filename .. '} from ' .. filename ..'\\clearpage')  
    end
    return t
end
scandir("C:/Users/Uwe/LuaLula/includes/")
\end{luacode}

\end{document}
4

This solution is only for Microsoft Windows users. For Linux, MAC, Unix users, you have to adapt the batch-related parts. Sorry for this inconvenience and thank you for your cooperation.

This code below was actually also prepared several decades ago here (click). Compile with pdflatex -shell-escape filename. Make sure that

  • the input files to be included are put in a sub directory Sub-Dir.
  • no spaces in path are allowed (to simplify the code).

Generic Minimal Working Example

% filename.tex

\documentclass[preview,border=12pt,12pt,varwidth]{standalone}

\usepackage{filecontents}
\begin{filecontents*}{batch.txt}
rem batch.bat
echo off

rem %1 path (relative to the main input file) to the files to be iterated 
rem %2 output file name
rem remaining args represent the extension of file to be iterated

set curdir=%CD%
cd "%~1"
shift

rem output must be enclosed with "" to allow spaces in the path
set output="%curdir%\%~1.list"

if exist %output% del %output%
copy nul %output%
shift

:loop
if "%~1"=="" goto :eof
dir /b *.%~1 >> %output%
shift
goto :loop
\end{filecontents*}


\begin{filecontents*}{oh-my-ghost.tex}
No body no body but you!
\[
E\not = mc^2
\]
\end{filecontents*}

\begin{filecontents*}{hahaha.tex}
PSTricks is fun!
\[
pV = nRT
\]
\end{filecontents*}


\immediate\write18{%
    del batch.bat && 
    rename batch.txt batch.bat && 
    move oh-my-ghost.tex Sub-Dir/oh-my-ghost.tex && 
    move hahaha.tex Sub-Dir/hahaha.tex
}


\newread\reader
\newcount\TotalFiles    


\makeatletter
\newcommand\IterateInputFiles[2][tex]{%
% #1: directory path with a trailing /
% #2: a list of file extensions: tex 
\immediate\write18{batch "#2" \jobname\space #1}
\openin\reader=\jobname.list\relax
\loop
    \read\reader to \filename
    \unless\ifeof\reader
    \filename@parse{\filename}
    \section{\filename@base}% change to \chapter if you want 
    \include{"#2\filename@base"}
    \advance\TotalFiles1\relax
\repeat
\closein\reader
}
\makeatother



\begin{document}
\IterateInputFiles{Sub-Dir/}

\section{Summary}
There is(are) \the\TotalFiles\ file(s) in total.
\end{document}

Output

The following output is the proof that I am not lying.

enter image description here


Multi-platform Version

% filename.tex

\documentclass[preview,border=12pt,12pt,varwidth]{standalone}

\newif\ifDOS
%\DOStrue
\DOSfalse

\usepackage{filecontents}
\ifDOS
\begin{filecontents*}{batch.txt}
rem batch.bat
echo off

rem %1 path (relative to the main input file) to the files to be iterated
rem %2 output file name
rem remaining args represent the extension of file to be iterated

set curdir=%CD%
cd "%~1"
shift

rem output must be enclosed with "" to allow spaces in the path
set output="%curdir%\%~1.list"

if exist %output% del %output%
copy nul %output%
shift

:loop
if "%~1"=="" goto :eof
dir /b *.%~1 >> %output%
shift
goto :loop
\end{filecontents*}
\else
\begin{filecontents*}{batch.txt}
#!/bin/bash
# bash batch.sh Sub-Dir output tex

# $1 path (relative to the main input file) to the files to be iterated
# $2 output file name
# remaining args represent the extension of file to be iterated

output="$2.list"

if [ -e "$output" ]; then
    rm "$output"
fi

for ext in ${@:3}; do
    ls "$1"/*."$ext" >> "$output"
done
# $ (to squelch bad syntax highlighting in my editor)
\end{filecontents*}
\fi

\begin{filecontents*}{oh-my-ghost.tex}
No body no body but you!
\[
E\not = mc^2
\]
\end{filecontents*}

\begin{filecontents*}{hahaha.tex}
PSTricks is fun!
\[
pV = nRT
\]
\end{filecontents*}


\ifDOS
\immediate\write18{%
  del batch.bat &&
  rename batch.txt batch.bat &&
  move oh-my-ghost.tex Sub-Dir/oh-my-ghost.tex &&
  move hahaha.tex Sub-Dir/hahaha.tex
}
\else
\immediate\write18{%
  mv batch.txt batch.sh &&
  mkdir -p Sub-Dir &&
  mv oh-my-ghost.tex hahaha.tex Sub-Dir/
}
\fi


\newread\reader
\newcount\TotalFiles

\makeatletter
\newcommand\IterateInputFiles[2][tex]{%
% #1: directory path with a trailing /
% #2: a list of file extensions: tex
\ifDOS
\immediate\write18{batch "#2" \jobname\space #1}
\else
\immediate\write18{bash batch.sh "#2" \jobname\space #1}
\fi
\openin\reader=\jobname.list\relax
\let\filename\relax
\loop
  \read\reader to \filename
  \typeout{<<< here again}
  \unless\ifeof\reader
  \filename@parse{\filename}
  \section{\filename@base}% change to \chapter if you want
  \include{"#2\filename@base"}
  \advance\TotalFiles1\relax
\repeat
\closein\reader
}
\makeatother

\begin{document}
\IterateInputFiles{Sub-Dir/}

\section{Summary}
There is(are) \the\TotalFiles\ file(s) in total.
\end{document}
  • Will this work on Linux and the mac also? – Nasser Sep 13 '14 at 7:55
  • @Nasser: No. It is only for Windows. – kiss my armpit Sep 13 '14 at 7:58
  • You have to rewrite it, in it's current form the system call is Windows-only. – Uwe Ziegenhagen Sep 13 '14 at 7:59
  • Would you be okay with me editing-in a Bash version of your script? – Sean Allred Sep 13 '14 at 15:50
  • 1
    @Ohmyghost Yes, it's just for consistency :) – Sean Allred Sep 13 '14 at 17:52

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.