Reputation: 424
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
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
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
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