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

How would I open two files and join then into one file with file 1 output being column 1 and file 2 being column 2. for example:
file 1 looks like this
123455 c c
323333 c c
543212 c c
and
file 2 looks like this
fi1234 4 3
dtt234 4 3
3555t2 4 3
and i would want my joined file to look like this
123455 c c fi1234 4 3
323333 c c dtt234 4 3
543212 c c 3555t2 4 3
Ive tried something like the following which did not work.

open(IN, "file1") || or die; open(IN2, "file2") || or die; open(OUT, ">>joinfile") || or die; for my $file1 (<IN>) { chomp $file1; for my $file2 (<IN2>) { chomp $file2; print OUT "$file1 $file2\n"; } }
This printed everything in file 1 three times. Thanks for any help.

Replies are listed 'Best First'.
Re: joining to files into columns
by diotalevi (Canon) on May 18, 2006 at 22:29 UTC

    The standard unix program paste does exactly this.

    $ paste file1 file2 123455 c c fi1234 4 3 323333 c c dtt234 4 3 543212 c c 3555t2 4 3

    ⠤⠤ ⠙⠊⠕⠞⠁⠇⠑⠧⠊

    A reply falls below the community's threshold of quality. You may see it by logging in.
Re: joining to files into columns
by runrig (Abbot) on May 18, 2006 at 22:25 UTC
    One helpful hint: you almost never want to read a file in a "for" loop as you have it. You are reading the entire file into memory. If you don't care about reading the whole thing into memory, then you may as well do:
    my @file1 = chomp( <IN1> ); my @file2 = chomp( <IN2> ); my $last = (@file1 > @file2) ? $#file1 : $#file2; for my $line (0..$last) { print "$file1[$line] $file2[$line]\n"; }
    If you don't want to read the entire contents into memory, then you'll need to eliminate the inner loop. Something like:
    { my $line1 = <IN1>; my $line2 = <IN2>; last unless $line1 or $line2; chomp for $line1, $line2; print "$line1 $line2\n"; redo; }
Re: joining to files into columns
by GrandFather (Saint) on May 18, 2006 at 22:55 UTC

    The following (untested) code should help:

    use strict; use warnings; open IN, '<', "file1" or die "Failed to open file1: $|"; open IN2, '<', "file2" or die "Failed to open file2: $|"; open OUT, '>>', "joinfile" or die "Failed to open joinfile: $|"; while (! eof (IN) || ! eof (IN2)) { my $file1 = <IN> || '!! missing file1 line !!'; my $file2 = <IN2> || '!! missing file2 line !!'; chomp $file1; chomp $file2; print OUT "$file1 $file2\n"; }

    Note that a few things have been cleaned up:

    • strictures have been added
    • The opens have changed to 3 parameter opens
    • Diagnostic error messages have been added to the dies

    If you want to stop when either file runs out of lines change the || to an &&.


    DWIM is Perl's answer to Gödel
Re: joining to files into columns
by johngg (Canon) on May 18, 2006 at 22:23 UTC
    That's because you read a line from file1 in the outer loop and, for that line, read and printed the three lines from file2 in the inner loop. If you can be sure that there are the same number of lines in each file you could do this (not tested).

    use strict; use warnings; open(IN, "file1") || or die $!; open(IN2, "file2") || or die $!; open(OUT, ">>joinfile") || or die $!; while(defined(my $f1 = <IN>) { chomp $f1; my $f2 = <IN2>; print OUT "$f1 $f2"; }

    That ought to do the trick. It is always good practice to put use strict; and use warnings; at the beginning of your scripts to help catch errors. Also, did you mean to append to "joinfile" with your use of >>? Use a single > to write to a new file or overwrite an existing one.

    Cheers,

    JohnGG

Re: joining to files into columns
by rodion (Chaplain) on May 18, 2006 at 22:15 UTC
    You've got a loop within a loop, when you want just one loop going through both files. Change the line that reads "for my $file2 (<IN2>){" to "$file2 = <IN2>;", and remove the corresponding bracket for the "for" loop, and you should be OK

      This kind of has also been discussed extensively only a few days ago in this thread.

      <shameless self="ad">
      My solution generalized to an arbitrary number of files and lines per file. Since the requirements here are slightly different, a trivial modification is in order.
      </shameless>

Re: joining to files into columns
by dsheroh (Monsignor) on May 18, 2006 at 22:38 UTC
    Others have already explained why your code doesn't do what you expected, but there's also an easier way to do this (assuming you're on a *nix box) outside of Perl: Use the paste command:
    $ cat foo aaa bbb ccc $ cat bar xxx yyy zzz $ paste foo bar aaa xxx bbb yyy ccc zzz $
      ...assuming you're on a *nix box...
      ...or have *nix utilities installed (on a Win32 box) or even ppt (on any box with Perl installed).