Note that except for the additional code in attempt 2, all the code actually does the opposite of what OP asked. As you can see in attempt 2, it is easy to adapt the commands.
I had a textfile with 1.108.752 lines in it, about 83 MB in size. I wanted to get 46.744 lines from it, ranging between the 15th and the 1.108.716th line, which is about every 24th line on average.
tl;dr;
Second attempt is faster than first. Third only works for fewer lines.
First Attempt (bad)
For every line I want, sed
reads lines from the start of the textfile, but not print them (-n
). When it reaches the line I want, print it (p
), then quit (q
) instead of reading to the end of the file. Then do that again for the next linenumber.
Obviously, this takes a little longer each run, because sed
has to go through more lines than before each time.
If I calculated that right, in my case that would take about 307332472188 passes through the textfile overall. Oh my.
Note that for this approach the order of lines is irrelevant in the linenumbers file:
while read line; do
sed -n "${line}{p;q}" "${INFILE}"
done
Timing results: 2568.80s user 256.10s system 92% cpu 51:00.37 total
. No good.
Second Attempt (better)
This reads the linenumbers from the file and appends a p
(again, for printing this line). This string is piped to the next sed
, which reads from a file (-f
), which here is STDIN
written as -
, which each time is the output from the first sed
, which is actually the linenumber to be printed:
sed 's/$/p/' "${LINENUMS}" | sed -n -f - "${INFILE}"
Timing results: 146.54s user 0.18s system 100% cpu 2:26.70 total
. Pretty good!
If you want to not print the lines from the linefile (like OP wanted to do), slightly change the command so that linenumbers are being deleted instead of printed, and print all other lines instead of deleting them (-n):
sed 's/$/d/' "${LINENUMS}" | sed -f - "${INFILE}"
Third Attempt (badder)
This wasn't working for me at all because I had too many lines I wanted to extract. It should work for (much) fewer lines though, but I don't know the limit to that.
I tried to create a long string for sed, which I expected would lead to sed
going through the file only once (!), not printing anything except the linenumbers from the string:
sed -n "12p;15p;24p;345p;...;12345;" ${INFILE}"
but that would result in a string about 420076
characters long, which upon pumping into sed
simply led to sed: Argument list is too long
. Which is understandable.