여러 개의 파일(>150)과 여러 개의 열(>150)이 있습니다. 대부분의 헤더는 공통적이지만 아래 표시된 대로 다른 순서로 나타납니다.
파일 1:
Col1 Col2 Col3 Col4 Col5
A B C D E
파일 2:
Col1 Col4 Col3 Col5
P Q R S
원하는 출력:
Col1 Col3 Col4 Col5
A C D E
P R Q S
또는 거의 30~40개의 파일이 공통 헤더 세트를 갖습니다(순서는 여전히 다릅니다). 헤더(및 해당 데이터)가 전체 파일 더미에서 동일한 순서로 표시되도록 정렬하는 데 도움을 줄 수 있는 사람이 있다면 4~5개의 파일 더미에서 일반적이지 않은 열을 제거하고 공통 열을 병합할 수 있습니다. 세트 .
답변1
GNU awk는 원하는 수의 파일을 처리할 수 있습니다(모든 파일 내용은 메모리에 저장되므로 시스템의 메모리 용량에 따라 다릅니다).
gawk '
# examine the headers for this file
FNR == 1 {
num_files++
delete this_headers
for (i=1; i<=NF; i++) {
all_headers[$i]++
this_headers[i] = $i
}
next
}
# this is a line of data
{
n++
for (i=1; i<=NF; i++) {
data[n][this_headers[i]] = $i
}
}
END {
# find the headers that are common to all files
for (header in all_headers) {
if (all_headers[header] == num_files)
common_headers[header]
}
# sort arrays by index, alphabetically
PROCINFO["sorted_in"] = "@ind_str_asc"
# print out the common headers
for (header in common_headers) {
printf "%s ", header
}
print ""
# print out the data
for (i=1; i<=n; i++) {
for (header in common_headers) {
printf "%s ", data[i][header]
}
print ""
}
}
' file1 file2
산출
Col1 Col3 Col4 Col5
A C D E
P R Q S
답변2
이 Perl 코드는 병합할 모든 파일을 수신하고 모든 파일의 헤더에서 공통 헤더를 결정한 다음 열 인쇄 순서를 재정렬하여 파일을 출력합니다.
perl -wMstrict -Mvars='*ARGV_orig,*comm_hdr,*prev,*h' -lne '
BEGIN{
@::ARGV_orig = @ARGV;
$::prev = q//;
sub trim {
my ($str) = @_ ? @_ : $_;
for($str) {
s/^\s*//;s/\s*$//;
}
return $str;
}
sub intersection(\@\@) {
@{$_[0]} > @{$_[1]} and @_ = reverse @_;
my @smaller = @{ +shift };
my @larger = @{ +shift };
my @common;
for my $e (@smaller) {
push @common, $e
if grep { $_ eq $e } @larger;
}
return @common;
}
sub col_print_order {
my @common_hdr = @{ $_[0]->{common_header} };
my @header2prn = @{ $_[0]->{header_2print} };
my @reorder;
for my $e (@common_hdr) {
if ( -1 < (my ($l) = grep { $header2prn[$_] eq $e } 0..$#header2prn) ) {
push @reorder, $l;
}
}
return @reorder;
}
}
if ( $ARGV ne $::prev ) {
$::h{$ARGV}{header} = $_;
my @A = split;
@::comm_hdr = @::comm_hdr ? intersection(@::comm_hdr, @A) : @A;
$::prev = $ARGV;
} else {
push @{ $::h{$ARGV}{data} }, $_;
}
END{
local $, = chr(32);
my @comm_hdr_sorted = sort @::comm_hdr;;
print @comm_hdr_sorted;
for my $argv (@::ARGV_orig) {
my @current_header = split /\s+/, trim $::h{$argv}{header};
my @order = col_print_order({
common_header => \@comm_hdr_sorted,
header_2print => \@current_header,
});
my @file = @{ $::h{$argv}{data} };
for my $line_num ( 0..$#file ) {
my $line = trim $file[$line_num];
my @fields = split /\s+/, $line;
print @fields[ @order ];
}
}
}
' yourfile1 yourfile2 yourfile3 # ... specify all your filenames to be merged here
산출
Col1 Col3 Col4 Col5
A C D E
P R Q S
답변3
코드를 파일로 저장열 병합, 실행 가능하게 만들고 시작하십시오.
mergecols -C1=0,2,3,4 -C2=0,2,1,3 file1 file2
#!/usr/bin/perl -s
# mergecols
# -C1=0,2,3,4 columns from file 1
# -C2=0,2,1,3 columns from file 2
# file1 input file 1
# file2 input file 2
($f1,$f2) = @ARGV;
@t1 = map { [split] } do { local @ARGV=($f1); <> };
@t2 = map { [split] } do { local @ARGV=($f2); <> };
@c1 = split /,/, $C1;
@c2 = split /,/, $C2;
for ( $i=0; $t1[$i] or $t2[$i]; $i++ ) {
print join ' ', @{$t1[$i]}[@c1], "\n" if $t1[$i];
print join ' ', @{$t2[$i]}[@c2], "\n" if $t2[$i];
}