52

Assume I have many TeX files. For the sake of simplicity, also asssume they are in a single folder or directory.

I want to input all files from within my main LaTeX document. Actually I can create a list of those files using C# in advance.

To enrich my view about LaTeX or TeX, could you tell me whether or not this job can be done only by using pure TeX or LaTeX?

4
  • As I've commented next to Herbert's answer, it is *nix dependent. As it relies on the OS to work, any solution of this type will dependent on which system you use.
    – Joseph Wright
    Commented Dec 23, 2010 at 17:44
  • @xport. No, it's just that TeX is perhaps not the best way to do it. I'd probably write a batch file to set things up, writing a suitable input file using that and then running TeX with my intermediate file as input. However, that's not really a question for this site as it's about Windows batch file programming. You've also pointed out that you can create the list in advance in C#, which is also a reasonable approach and one I guess you can implement yourself.
    – Joseph Wright
    Commented Dec 23, 2010 at 17:50
  • 1
    @xport. TeX does not do any handling of file processing beyond reading or writing individual files. Herbert's solution uses the Unix shell to do the work, and the same can be achieved in Windows. However, these solutions don't use TeX to do the work, they use the OS.
    – Joseph Wright
    Commented Dec 23, 2010 at 18:35
  • 3
    I'm not sure, but you could try to use \app@exe{cmd /c dir /b *.txt > \jobname.tmp} in Herbert's answer. On a sidenote, his code does work in Windows if you have the proper *nix tools provided by Cygwin or MSys. IMHO those tools give us more confidence than their Windows counterparts. Commented Jul 30, 2011 at 19:55

6 Answers 6

39
+50
\documentclass{article}
\makeatletter
\def\app@exe{\immediate\write18}
\def\inputAllFiles#1{%
  \app@exe{ls #1/*.txt | xargs cat >> #1/\jobname.tmp}%
  \InputIfFileExists{#1/\jobname.tmp}{}{}
  \AtEndDocument{\app@exe{rm -f #1/\jobname.tmp}}}
\makeatother
\begin{document}

\inputAllFiles{.}% from the current dir 

\end{document}

Not really difficult. It is only an appetizer of how it can be done. This one only reads files *.txt. You have to run it with pdflatex -shell-escape test

6
  • 6
    As Ryan pointed out, this is an OS-depend solution. It will fail on Windows, for a start.
    – Joseph Wright
    Commented Dec 23, 2010 at 17:39
  • 3
    I think the second \app@exe should be \app@exe{rm -f \jobname.tmp}. It only works for this example because #1 is .. It'd also be simpler to just run \app@exe{cat #1/*.txt > \jobname.tmp}.
    – TH.
    Commented Dec 23, 2010 at 20:50
  • Does this delete the files after they are accessed? Why is there a rm -f \jobname.tmp?
    – Village
    Commented Dec 17, 2011 at 23:44
  • all files are read and saved in \jobname.tmp, when is deleted after reading it into TeX
    – user2478
    Commented Dec 18, 2011 at 8:39
  • 1
    I wish you could do this on Windows.
    – vy32
    Commented Feb 18, 2017 at 17:26
29

If there is some sort of naming convention that is used for the files than this can be done as in Can i automatically load chapters and sections based on the filesystem?

\documentclass{article}

\newcommand*{\MaxNumOfChapters}{10}% Adjust these two settings for your needs.
\newcommand*{\MaxNumOfSections}{6}%

\usepackage{pgffor}%

\begin{document}
\foreach \c in {1,2,...,\MaxNumOfChapters}{%
    \foreach \s in {1,2,...,\MaxNumOfSections}{%
        \IfFileExists{Chapter\c/Section\s} {%
            \input{Chapter\c/Section\s}%
        }{%
                % files does not exist, so nothing to do
        }%
    }%
}%
\end{document}

This assumes that there is a directory for each chapter named Chapter<i> directory contains files named Section<n>. Should be able to customize this depending on your specific case.

This should work across different operating systems.

If there is not specfic naming convention, you can adjust this to process a list of files generated by your C# program. For example, if the C# program can generate ListOfFiles.tex as

\newcommand*{\ListOfFiles}{%
    Chapter1/Section1,
    Chapter1/Section2,
    Chapter1/Section3,
    Chapter2/Section1,
    Chapter2/Section2
}%

then you can process this as:

\documentclass{article}%
\usepackage{pgffor}%

\input{ListOfFiles}%

\begin{document}%
\foreach \c in \ListOfFiles {%
    \input{\c}%
}%
\end{document}
1
  • 1
    Warning to casual user: I had set up my list with commas at the start of the lines instead of the end (as here), with the result that I had inadvertently added empty spaces at the end of the file names: compilation failed when \includegraphics unsuccessfully searched for section .pdf (with an unwanted extra space). [I was using \includegraphics instead of \input but otherwise very similar code adapted from Peter Grill's suggestion]. Bottom line (pun intended): end your lines with % (or with a comma) to avoid adding unwanted spaces.
    – PatrickT
    Commented Mar 18, 2017 at 9:59
21

A LuaTeX solution:

the TeX driver:

\directlua{dofile("inputall.lua")}

\bye

and the Lua input file inputall.lua:

function dirtree(dir)

  if string.sub(dir, -1) == "/" then
    dir=string.sub(dir, 1, -2)
  end

  local function yieldtree(dir)
    for entry in lfs.dir(dir) do
      if not entry:match("^%.") then
        entry=dir.."/"..entry
          if lfs.isdir(entry) then
            yieldtree(entry)
          else
            coroutine.yield(entry)
          end
      end
    end
  end

  return coroutine.wrap(function() yieldtree(dir) end)
end


for i in dirtree(lfs.currentdir()) do
  local filename = i:gsub(".*/([^/]+)$","%1")
  tex.sprint("\\input " ..  filename .. " ")
end

This recurses down a directory tree and inputs all the file found. (Found the dirtree iterator in the Lua users wiki.)

7
  • The answer should work in both plain and LaTeX. I bet that in a few years, this answer would be a standard answer. -- But I admit that I like to give a LuaTeX answer even if the OP does not ask for it or runs a engine different to LuaTeX.
    – topskip
    Commented Dec 24, 2010 at 20:22
  • 1
    +1 for the interesting answer. Would it be possible to add a complete minimal example we could try at home? Thanks. Commented Mar 20, 2011 at 9:43
  • @topskip sorry, it's still not the standard answer: tex.stackexchange.com/questions/509488/…
    – Skillmon
    Commented Sep 23, 2019 at 17:51
  • @topskip filename may contain spaces. Commented Oct 22, 2021 at 9:28
  • @JérômeLAURENS I know, but I have to admit I don't understand what you are trying to tell me. Is the solution above not working for files with spaces in file names?
    – topskip
    Commented Oct 22, 2021 at 9:32
10

I don't know whether you can; you probably can't, and if you could, the facilities for it are almost certainly extremely limited and likely based on \write18, which makes the OS do all the work anyway. However, I don't think you should, since it is far from being a typesetting task, which is the only kind of job TeX is designed to do. Consider:

  • If all you want is a list of \input{filename.tex}'s, and if you can already programmatically create a list of filenames using some other language, then you can also generate a TeX file (or file fragment) using that language.

  • I don't know how you created these files, but if you did it by hand, then perhaps you gave them meaningful names, like introduction.tex, body.tex, and conclusion.tex. No form of automatic sorting will give you the right order, so you're back to creating a list by some other means, for which see the previous point.

  • How many times are you going to TeX this document? If only once, you may as well just write the names in by hand and concentrate on your writing and/or other TeX coding which it contains.

Basically, this is a bookkeeping task which doesn't depend on anything within a TeX document, and therefore is better done by one of the many scripting languages which support filesystem interaction (not to mention programming in general) to a far greater extent than TeX itself.

3
  • thanks for answering. I have made the list of file names in advance using C# as I mentioned above. You can see my effort here :-) tex.stackexchange.com/questions/6547/… Commented Dec 23, 2010 at 16:53
  • 1
    @xport: My point is that the only way to include files is by individual \input commands, and the only way to access the filesystem is through \write18 (i.e. invoking another program) and if you're going to do that, you may as well have another program write out a TeX file fragment itself (which includes all your files) and then use just one \input to include it, rather than force TeX to do something it does quite badly.
    – Ryan Reich
    Commented Dec 23, 2010 at 23:51
  • @RyanReich, imho it can be convenient to do everything in one action, for this sort of reason DVD players can usually read CDs so you don't have to buy two machines, even though listening to CDs in a DVD player is a questionable practice.
    – PatrickT
    Commented Dec 16, 2014 at 12:20
3

Here's a simpler Luatex solution

function inputAll(dir)
    for file in lfs.dir(dir) do
        fullpath = dir .."/".. file
        modeAttr = lfs.attributes(fullpath, "mode")
        extension = string.sub(file,#file-3,#file)
        if modeAttr == "file" and extension == ".tex" then
            tex.sprint("\\input{" .. fullpath .. "}")
        end
    end
end

Call using something like

\directlua{
  dofile("scripts/inputall.lua");
  inputAll("Skills")
}
2
  • Is there way to sort the files? For example, Chapter.01 then Chapter.02 ... Commented Sep 1, 2021 at 22:20
  • A version without an external file, for example with the luacode package, would be very helpful Commented Oct 22, 2021 at 9:43
2

Here's a platform independent approach (although it requires Java) using texosquery.

\documentclass{article}

\usepackage{texosquery}

\begin{document}
% Find all files matching the (anchored) regular expression .+\.c
% in the current directory and store the result in a comma-separated
% list in the command \result
\TeXOSQueryFilterFileList{\result}{,}{.+\string\.c}{.}

\ifx\result\empty
 Query failed!
\else
 \makeatletter
 \@for\thisfile:=\result\do{File: \thisfile. }
 \makeatother
\fi
\end{document}

If you have Java 8 and texosquery-jre8 is on the restricted list (which it is for TeX Live 2017 onwards), then change the texosquery.cfg file to include:

\def\TeXOSInvokerName{texosquery-jre8}

and uncomment

\TeXOSQueryAllowRestricted

(MiKTeX users additionally need to enable piped-shell escape support.) Once this has been set up then texosquery-jre8 can be run in restricted mode, which is safer than using -shell-escape.

There are variations of \TeXOSQueryFilterFileList, such as \TeXOSQueryFilterFileListDateAsc to order by date etc.

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .