
シェル スクリプトに関するヘルプが必要です。キーと値を含む 1.2 GB 程度の大きなファイルが 2 つあります。キーに基づいて両方のファイルを比較し、3 番目のファイルの値とファイル 1 の一意の値の違いを保存する必要があります。
ファイル1:
test1 marco;polo;angus
test2 mike;zen;liza
test3 tom;harry;alan
test4 bob;june;janet
ファイル2:
test1 polo;angus
test2 mike
test4 bob;janet
ファイル 1 の最初の 2 列をファイル 2 と比較し (ファイル 2 の最初の 2 列の内容全体を検索)、一致する場合は値の差を出力します。次に、ファイル 1 の 2 行目を検索します。ファイル 1 で一意のキーも出力する必要があります。
期待される出力:
test1 marco
test2 zen;liza
test3 tom;harry;alan
test4 june
私が持っているファイルは巨大で、約 100,000 行が含まれているため、実行を高速化したいと考えています。これは、#!/usr/bin/env bash.
たとえば、シェル スクリプトを使用して実行されています。
1332239_44557576_CONTI Lased & Micro kjd $353.50_30062020_lsdf3_no-rule 343323H;343434311H;454656556H;343343432H
これは単純なテキストファイルで、キーは ( 1332239_44557576_CONTI Lased & Micro kjd $353.50_30062020_lsdf3_no-rule
)、値は次のようになります: ( 343323H;343434311H;454656556H;343343432H
)
ファイル 2 は常にファイル 1 のサブセットになります。ファイル 2 に存在しない値 (キーに対して) とファイル 1 内の一意の値を見つける必要があります。
答え1
Perl スクリプトの使用:
あなたが検索しているものと仮定しますファイル1に基づくファイル2逆は成り立ちません。ファイル2に基づいてファイル1を検索したい場合は、もう一つのforループを追加するfile2 辞書(ハッシュ) 用。
データファイル:
$ cat file1.txt
test1 marco;polo;angus
test2 mike;zen;liza
test3 tom;harry;alan
test4 bob;june;janet
$ cat file2.txt
test1 polo;angus
test2 mike
test4 bob;janet
脚本 :
#!/usr/bin/perl
use warnings;
use strict;
my $file1=$ARGV[0];
my $file2=$ARGV[1];
my %dict1; #Stores file1 unique key and value pairs in this dictionary ( HASH in perl )
my %dict2; #Stores file2 unique key and value pairs in this dictionary ( HASH in perl )
my %output; #This is output dictionary after processing all the data to print it out
open(F1,'<',$file1) or die "File not found $file1";
open(F2,'<',$file2) or die "File not found $file2";
#Store both file's contents in %dict1 and %dict2 respectively
while(<F1>)
{
my ($key,$value) = split(/\s+/,$_);
$dict1{$key} = $value;
}
while(<F2>)
{
my ($key,$value) = split(/\s+/,$_);
$dict2{$key} = $value;
}
#Get the unique(difference) value from file2 based in the values in file1
foreach my $k ( keys %dict1 )
{
if ( defined $dict2{$k} )
{
my @dict1values=split(";",$dict1{$k});
my @dict2values=split(";",$dict2{$k});
foreach (@dict1values)
{
if ( $dict2{$k} !~ /[;]*?$_[;]*?/) {
$output{$k} .=$_.";";
}
}
} else {
$output{$k}=$dict1{$k};
}
}
foreach my $ke (sort(keys(%output)))
{
print "$ke $output{$ke}\n" if ( defined($output{$ke}) );
}
出力:
$ ./testing.pl file1.txt file2.txt
test1 marco;
test2 zen;liza;
test3 tom;harry;alan
test4 june;
答え2
これはawk非常に高速なバージョンです。
要求されたフィールド パターン [文字列:キー][スペース|";"][文字列][スペース|";"] などに従うものであれば何でも機能します。
$ cat file1;echo "";cat file2
test1 marco;polo;angus
test2 mike;zen;liza
test3 tom;harry;alan
test4 bob;june;janet
test1 polo;angus
test2 mike
test4 bob;janet
$ awk -F '[ ;]' '
NR==FNR{ for(i=2;i<=NF;i++){ k[$1,$i]++ } }
NR!=FNR{ for(i=2;i<=NF;i++){ k[$1,$i]++ } }
END{ for(i in k){
if(k[i]==1){
split(i,arr_i,SUBSEP);
k_e[arr_i[1]]=k_e[arr_i[1]]""arr_i[2]";"
}
}
for(i in k_e){
print i" "k_e[i]
}
}' file1 file2 | sort | sed 's/.$//'
test1 marco
test2 liza;zen
test3 harry;alan;tom
test4 june