Is there an easy way to read arbitrary lines from a file? For example "read line number 12" or "read backwards from last line to first line" or "read lines 1,3,5...".

  • You can use the packages listings or fancyvrb – Marco Daniel May 7 '11 at 11:36
  • @Macro: Yes, but AFAIK unfortunately they can't do something like "read backwards from last line to first line" (Not a good example anyway) or remove the last n lines, because both don't know the number of total lines. – Martin Scharrer May 7 '11 at 15:11

No, you can't read arbitrary lines, but you can't do that in most other programming languages either. You have to read line after line from the beginning. Apart from the \read primitive, there is also the \readline primitive which reads a line verbatim. You can use that to save all lines in macros and use these afterward:

  \advance\linecnt by \@ne
  \readline\myread t\expandafter o\csname line-\number\linecnt\endcsname
| improve this answer | |
  • I do not understand how can I use macros which is contain the lines? like \line-12 ? – sergiokapone Jan 16 '15 at 22:20
  • @sergiokapone You have to use it like \csname line-12\endcsname. – Henri Menke May 12 '15 at 20:56
  • Shouldn't it be \readline\myread to \expandafter\csname line-\number\linecnt\endcsname ? – Andrew Feb 10 '17 at 12:36

TeX is able to read lines from a file as long as they have balanced braces. This is accomplished through \openin and \read.

\read\myread to \command

Now \command will expand to the contents of the first line in file.dat and a subsequent \read\myread to \command will do the same with the following line. The end of the file can be tested with \ifeof\myread, but one should always keep in mind that TeX appends an empty line to each file. The symbolic name \myread can be reused after having closed the file with \closein\myread.

It must be mentioned the possibility of calling, via "shell-escape", external utilities that may be faster and more flexible.

| improve this answer | |

What you are asking about here is "random access" to the lines of text file, which is not supported by any filesystem that I know of. Most programming languages have a seek function that can "jump" forward and backwards in a file by a given number of bytes. This works well in binary files or text files where every line is the same length since the byte offset of "jump to position x" can be calculated.

Unfortunately, most text files have a varying number of bytes per line so it is impossible to predict the offset at which a given line begins without reading the contents of the file. To get around this problem, you need to "index" the file in some way such that lines can be located in an arbitrary order. Two methods that I am aware of are:

  • Read the contents of the file, split it into lines and store the results in an array. The array index then provides random access to the file contents. This works well for small files.

  • For large files, you have to worry about running out of time or memory. A common trick to conserve memory is to scan the file and store the byte offset of each line in an array rather that the contents of the line its self. These offsets can then be fed to seek in order to locate a line in the file. Perl's Tie::File module uses this method along with some other tricks to represent large files as arrays.

Suppose we have the following input file:


With TeX you have two problems:

  1. You can only read the file one line at a time---no fancy tricks such as a seek method that lets you jump over content.

  2. Without the help of packages, no nice object that can be used as an array with operations like indexed lookup or maximum length.

Solution: Use LuaTeX

This is the easiest way to go since Lua tables make great array objects:


  % Read the contents of a file #1 to an array and store the array name in #2
    local input = io.open('#1', 'r')
    #2 = {}
    for line in input:lines() do
      table.insert(#2, line)

% Read the contents of io.in to foo

% Loop over foo any way you want. The Lua shortcut for table.getn(foo) is #foo,
% but the # character is also special to TeX which causes some confusion.
  for i = 1, table.getn(foo) do texio.write_nl(foo[i]) end}

  for i = table.getn(foo), 1, -1 do texio.write_nl(foo[i]) end}

  texio.write_nl("Odd entries only:")%
  for i = 1, table.getn(foo), 2 do texio.write_nl(foo[i]) end}


The lualatex log output is:

Odd entries only:

Lua FILE objects such as input also have a seek method that can be used to pull off advanced tricks.

| improve this answer | |

I was also interested in this problem and I found a solution using the package readarray:

1 row
2 row
3 row
4 row
5 row
6 row
7 row
8 row
9 row
10 row



%\ReadLine{<file name>} read one random line from file <file name>

%\ReadLine{<file name>}{<line number>} read one line with number <line number> from file <file name>

%\ReadLine{<file name>}{<first line>}{<last line>} read lines from file <file name> from <first line> to <last line>
\advance\i by 1
\loop\ifnum\value{someline} < \i





| improve this answer | |

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.