elef has asked for the wisdom of the Perl Monks concerning the following question:

I'd like to have a perl script create a tab delimited txt out of two text files, line by line.

I.e. I have:
File 1: one two three four File 2: A B C D
And I'd like the script to generate:
one[tab]A two[tab]B three[tab]C four[tab]D

Ideally, this would be done without reading any of the files into memory in full, as I'd like it to work on large files on systems with little memory. (Although I'd like to know how it's best done by reading the files into variables, God knows I need some guidance on arrays and the like.)

I feel like some sort of a while loop should work, but it would need to iterate through two files at once, which sounds tricky... Maybe I could create a while loop that goes through file 1, saves the current line no. and the current line content in variables, and embed another while loop in it that goes through file 2 and prints the output when it gets to the line number that loop 1 is at. That should work, but that way I'd loop through file 2 lots of times.

Any ideas for doing this in a more elegant/efficient way?

Update: solved, my favourite solution for files of equal length is (from almut):
while (my $col1 = <FILE1>) { chomp $col1; my $col2 = <FILE2>; print "$col1\t$col2"; }
And, if the two files may have a different number of lines, courtesy of BrowserUk and Marshall:
until(eof(ONE) and eof (TWO)) { my $one = <ONE>; my $two = <TWO>; $one ||= ""; $two ||= ""; chomp($one); chomp($two); print "$one\t$two\n"; }

Replies are listed 'Best First'.
Re: How do you create a tab delimited txt file from two files?
by almut (Canon) on Jul 29, 2010 at 08:01 UTC

    Open the two files, then read a line from each file on every iteration:

    while (my $col1 = <FILE1>) { chomp $col1; my $col2 = <FILE2>; print "$col1\t$col2"; }

      Ooooh, that's nice, I had no idea perl could do that. This is the sort of thing I was looking for.

      One issue, though: it seems to choke if the two files don't have the same number of lines. I could just count the lines in each and pad the shorter file with as many \n as required before starting the loop, but there has to be a better solution than that. Any tips?
        while (my $col1 = <FILE1>) { chomp $col1; last unless (my $col2 = <FILE2>); print "$col1\t$col2"; }
        the above will stop at the end of the shorter file
        print "Good ",qw(night morning afternoon evening)[(localtime)[2]/6]," fellow monks."
Re: How do you create a tab delimited txt file from two files?
by roboticus (Chancellor) on Jul 29, 2010 at 08:01 UTC
Re: How do you create a tab delimited txt file from two files?
by BrowserUk (Patriarch) on Jul 29, 2010 at 08:03 UTC
    #! perl -slw use strict; open ONE, '<', $ARGV[0] or die $!; open TWO, '<', $ARGV[1] or die $!; until( eof( ONE ) ) { chomp( my $one = <ONE> ); chomp( my $two = <TWO> ); print "$one\t$two"; } close ONE; close TWO; __END__ c:\test>junk11 file1 file2 one 1 two 2 three 3 four 4 five 5 six 6 seven 7 eight 8 nine 9 ten 10

      I consider the file1 and the file2 contents are equal numbers

      use strict; use warnings; ### open the first file and store in to a array format open (F1, "file1.txt") || die "Cannot open the input file : $!"; my @file1=<F1>; close (F1); ### open the second file and store in to a array format open (F2, "file2.txt") || die "Cannot open the input file : $!"; my @file2=<F2>; close (F2); my @file3; ### process each element and store the file1 and the corresponding ### value in second file in another one array for (my $i=0; $i<=$#file1; $i++) { chomp($file1[$i]); push @file3, "$file1[$i]\t$file2[$i]"; } ### print the array in a output file open (FOUT, ">Concat.txt") || die "Cannot create the output file"; print FOUT @file3; close (FOUT);
Re: How do you create a tab delimited txt file from two files?
by kejohm (Hermit) on Jul 29, 2010 at 10:41 UTC

    You could also look at the Tie::File module, which allows you to access a file as an array. Here is some sample code:

    #!perl use strict; use warnings; use feature qw(:5.10); use Tie::File; tie my @file1, 'Tie::File', 'file1' or die "Cannot tie file1: $!"; tie my @file2, 'Tie::File', 'file2' or die "Cannot tie file2: $!"; foreach(0 .. $#file1){ say "$file1[$_]\t$file2[$_]"; } untie @file1; untie @file2;

    You may have to do some error checking if you expect the files to be different lengths.

    Update: Link fixed.

      Thanks for that one, I'll keep it in mind. It seems that, despite what one might assume, Tie::File is part of the standard perl distribution and it doesn't read the whole file into memory. It should be come in pretty handy.
Re: How do you create a tab delimited txt file from two files?
by JavaFan (Canon) on Jul 29, 2010 at 10:31 UTC
    One of the rare cases where you don't want to enable warnings:
    use strict; use autodie; open my $one, "<", "data1"; open my $two, "<", "data2"; { my $line1 = <$one>; my $line2 = <$two>; last unless $line1 or $line2; chomp $line1; chomp $line2; print "$line1\t$line2\n"; redo; }
Re: How do you create a tab delimited txt file from two files?
by suhailck (Friar) on Jul 29, 2010 at 09:28 UTC
    An awk solution,

    awk 'NR==FNR{a[NR]=$0;next}{a[FNR]=a[FNR]"\t"$0}END{for(x=1;x<=FNR;x++ +){print a[x]}}' file1 file2



    ~suhail