I have a file with a list of lines I want to read from another file. I want to output those lines to a utility (grep) that lets me read the entire line and pull information from it. The file with the lines looks like this:

cat input.txt

For some reason I am stuck on this. I know sed can take a specific line number as an argument, but I can't figure how to get this into a variable to feed to it.

  • 1
    You have one file containing lines, and another file containing line numbers, and you want to produce a third file containing only the lines of the first file with the line numbers of the second file. - Did I understand your question correctly? – michas Jul 23 '14 at 21:51
awk 'NR==FNR{linesToPrint[$0];next}
     FNR in linesToPrint' line-numbers.txt file.txt

If I understand your problem correctly something like this should work:

for i in $(cat numbers.txt); do cat lines.txt|tail -n +$i|head -n 1; done

For each of the numbers in file "numbers.txt" it extracts the corresponding line of the other file and prints it.

The same thing with sed and xargs looks like this:

xargs -i sed "{}q;d" lines.txt <numbers.txt

Assuming michas' interpretation is correct, here's an awk solution:

awk 'FNR==NR{a[i++]=$0} # Process the first file
     FNR!=NR{           # Process the second file
         for (i in a){
                 print $0
     }' file_with_line_numbers other_file

In Perl:

perl -E '
        if($file2) { say if exists $lines{$.} }
        else       { $lines{$_}++             }
    }   continue   { if (eof){$.=0; $file2++} }'\
    file_with_line_numbers other_file
sed '/[^0-9]/d;s/.$/&p/' <input.txt |
sed -nf - file

That's two seds working together. The first makes some small attempt at ensuring it only edits appropriate lines by refusing to print any line that contains a single non-numeric character and only editing any lines containing at least one character. Basically its job, though, is just to transform your list of line numbers into:


The second reads its command script from standard input and does not print lines by default, so all of those lines edited by sed the first become a list of commands for the sed the second. It performs these commands on file.

Apparently a similar technique has already been recommended, but there is a fundamental difference between a process's invocation arguments and input. There are distinct limits on argument lists like:

some_process $(seq a billion)

That kind of thing is bound to fail, but, as long as the process knows how to handle it, its input is theoretically unlimited. So, in this case, sed reads a file - the |pipe - as input and processes it like a sed script, which is far different than handing it a string of same length on its command line at invocation.


Combine sed with xargs and printf:

sed -n $(xargs printf "%sp;" < input.txt) data

-n tells sed not to print lines unless you tell it to explicitly. xargs runs a command with the lines from standard input as its arguments. printf will format each argument as described. The $(...) above expands to (for your sample file):


which is a sequence of sed commands telling it to print lines 2088, 2089, 2095, and 2096.

In this way you read each file once, rather than many times for xargs -i sed "{}q" or piped head and tail.

  • This implodes if printf's output exceeds the system's ARGMAX limit, but probably line length would break it long before then. Strike that - ARGLEN even before that, I guess. – mikeserv Jul 30 '14 at 8:36

Another perl solution:

$ perl -MList::Util=any -nle '
    BEGIN {
        open $fh, "<", "input.txt";
        @lines = <$fh>;
        close $fh;
    print if any { $_ == $. } @lines;
' file

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.