Ahmet Said Akbulut
Ahmet Said Akbulut

Reputation: 424

Merge Two files of columns but insert columns of second file into columns of first file

Assume two files with same amount of columns.

file_A:

1 2 3 4 5
1 2 3 4 5
1 2 3 4 5
1 2 3 4 5
1 2 3 4 5

and

file_B:

A B C D E
A B C D E
A B C D E
A B C D E
A B C D E

I want to merge two files in order like

file_C:

1 A 2 B 3 C 4 D 5 E
1 A 2 B 3 C 4 D 5 E
1 A 2 B 3 C 4 D 5 E
1 A 2 B 3 C 4 D 5 E
1 A 2 B 3 C 4 D 5 E

I have found a solution in the community like this

paste file_A file_B | awk '{print $1,$6,$2,$7,$3,$8,$4,$9,$5,$10}'

But considering amount of columns is like 100 for each file or not constant, I want to know if there is a better method.

Thanks in advance.

Upvotes: 2

Views: 407

Answers (3)

thanasisp
thanasisp

Reputation: 5965

With one awk script parsing the files:

FNR==NR {
    rec[NR] = $0
    next
}

{
    split(rec[FNR], fields)
    for (i=1;i<=NF;i++) $i = fields[i] FS $i
    print
}

Usage:

awk -f tst.awk file_A file_B

Upvotes: 1

Bodo
Bodo

Reputation: 9855

You can use a loop in awk, for example

paste file_A file_B | awk '{ 
    half = NF/2; 
    for(i = 1; i < half; i++)
    {
        printf("%s %s ", $i, $(i+half));
    }
    printf("%s %s\n", $half, $NF);
}'

or

paste file_A file_B | awk '{ 
    i = 1; j = NF/2 + 1;
    while(j < NF)
    {
        printf("%s %s ", $i, $j);
        i++; j++;
    }
    printf("%s %s\n", $i, $j);
}'

The code assumes that the number of columns in awk's input is even.

Upvotes: 2

Timur Shtatland
Timur Shtatland

Reputation: 12347

Use this Perl one-liner after paste to print alternating columns:

paste file_A file_B | perl -F'\t' -lane 'print join "\t", @F[ map { ( $_, $_ + ( @F/2 ) ) } 0 .. ( $#F - 1 ) /  2 ];'

Example:

Create tab-delimited input files:

perl -le 'print join "\t", 1..5 for 1..2;' > file_A
perl -le 'print join "\t", "A".."E" for 1..2;' > file_B
head file_A file_B

Prints:

==> file_A <==
1       2       3       4       5
1       2       3       4       5

==> file_B <==
A       B       C       D       E
A       B       C       D       E

Paste files side by side, also tab-delimited:

paste file_A file_B | perl -F'\t' -lane 'print join "\t", @F[ map { ( $_, $_ + ( @F/2 ) ) } 0 .. ( $#F - 1 ) /  2 ];'

Prints:

1       A       2       B       3       C       4       D       5       E
1       A       2       B       3       C       4       D       5       E

The Perl one-liner uses these command line flags:
-e : Tells Perl to look for code in-line, instead of in a file.
-n : Loop over the input one line at a time, assigning it to $_ by default.
-l : Strip the input line separator ("\n" on *NIX by default) before executing the code in-line, and append it when printing.
-a : Split $_ into array @F on whitespace or on the regex specified in -F option.
-F'/\t/' : Split into @F on TAB, rather than on whitespace.

$#F : last index of the array @F with the input fields, split on tab.
0 .. ( $#F - 1 ) / 2 : array of indexes of the array @F, from the start (0) to half of the array. These are all indexes that correspond to file_A.
map { ( $_, $_ + ( @F/2 ) ) } 0 .. ( $#F - 1 ) / 2 : map takes the above array of indexes from 0 to half of the length of @F, and returns a new array, with twice the number of elements. Its elements alternate: (a) the index corresponding to file_A ($_) and (b) that index plus half the length of the array ($_ + ( @F/2 )), which is the corresponding index from file_B.
@F[ map { ( $_, $_ + ( @F/2 ) ) } 0 .. ( $#F - 1 ) / 2 ] : a slice of array @F with the specified indexes, namely alternating fields from file_A and file_B.

SEE ALSO:

perldoc perlrun: how to execute the Perl interpreter: command line switches
perldoc perldata: Slices

Upvotes: 1

Related Questions