TeX has support for file IO, and you can take advantage of this. To create a new input filehandle, you execute \newread\readFH
; at this point, \readFH
is a number representing a channel on which you can read or write (you've already seen one of these, the special channel 18
). To open the file, you run \openin\readFH=filename.ext
; now, reading from channel \readFH
will read lines from filename.ext
. To actually read from the file, you run \read\readFH to \nextline
; this reads one line from \readFH
and puts it in \nextline
. (With one caveat—see below.) Closing the file is then done with \closein\readFH
.
Note that this treats newlines as spaces; if you have a file containing e.g.
foo
bar
and read a line into \nextline
, it will be as though you wrote \def\nextline{foo }
. To avoid this, you set \endlinechar
to -1
.
Overall, then, your example would look like this:
\newread\myinput
% We use '\jobname.temp' to create a uniquely-named temporary file
\immediate\write18{some command > '\jobname.temp'}
\openin\myinput=\jobname.temp
% The group localizes the change to \endlinechar
\bgroup
\endlinechar=-1
\read\myinput to \localline
% Since everything in the group is local, we have to explicitly make the
% assignment global
\global\let\myresult\localline
\egroup
\closein\myinput
% Clean up after ourselves
\immediate\write18{rm -f -- '\jobname.temp'}
\dosomething{\myresult}
You could probably abstract this into a macro, but precisely what parts ought to be parametrized probably depends on your specific use case.
The one caveat I mentioned: \read
operates on balanced TeX text. This means that it will read more than one line if it has to in order to match braces, and it will finish all those lines. Thus, a single read from the file
Hello { all
you } people.
will result in the string Hello { all you } people.
Also, just for future reference: creating filehandles to write to is done with \newwrite
, you open them with \immediate\openout\writeFH=filename.ext
, you write to them with \immediate\write\writeFH{some text}
, and you close them with \immediate\closeout\writeFH
. Note that some text
is actual TeX; thus, macros are expanded and printing out e.g. backslashes or unbalanced curly brackets is non-trivial. (For backslashes, there's the LaTeX macro \@backslashchar
; see the TeX Stack Exchange question "How to make a real backslash (escape) character" for more general information. The short version is "play with catcodes.")
Furthermore, note the use of \immediate
for the writing commands but not the reading commands; if you don't use \immediate
with these, they'll be delayed until the output routine runs (that is, when TeX decides that the current page is finished and can be shipped out to the DVI/PDF). According to chapter 21 of The TeXBook, "The reason for this delay is that \write
is often used to make an index or table of contents, and the exact page on which a partcular item will appear is generally unknown when the \write
instruction occurs in mid-paragraph." (Pg. 227.) For \read
and friends, this clearly isn't a concern, hence the difference in behavior.
\immediate\write18{echo -n
pygmentize -N #1` > out.txt}` inside a\newcommand
definition and then including the output in your document:\input{out.txt}
iexec