Take the 2-minute tour ×
Unix & Linux Stack Exchange is a question and answer site for users of Linux, FreeBSD and other Un*x-like operating systems.. It's 100% free, no registration required.

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
2088
2089
2095
2096

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.

share|improve this question
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 at 21:51

6 Answers 6

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){
             if(FNR==a[i]){
                 print $0
             }
         }
     }' file_with_line_numbers other_file

In Perl:

perl -E '
    while(<>){
        chomp;
        if($file2) { say if exists $lines{$.} }
        else       { $lines{$_}++             }
    }   continue   { if (eof){$.=0; $file2++} }'\
    file_with_line_numbers other_file
share|improve this answer
awk 'NR==FNR{linesToPrint[$0];next}
     FNR in linesToPrint' line-numbers.txt file.txt
share|improve this answer

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
share|improve this answer

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):

2088p;2089p;2095p;2096p;

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.

share|improve this answer
    
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 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
share|improve this answer
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:

2088p
2089p
2095p
2096p

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.

share|improve this answer

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.