複数の.csvファイルの内容を1つの.csvファイルにマージするスクリプトを記述したい。つまり、他のすべてのファイルの列を最初のファイルの列に追加する。 「for」ループを使用してそうしようとしましたが、続行できませんでした。
Linuxでこれを行う方法を知っている人はいますか?
コマンドラインで指定された各ファイルの各行を読み取り、配列(@csv
)の要素に追加するPerlスクリプトを次に示します。入力がなくなると、@csv
の各要素が出力されます。
.csv
ファイルは、コマンドラインにリストされている順に追加されます。
[〜#〜] warning [〜#〜]:このスクリプトはすべての入力ファイルの行数が同じであると想定しています。ファイルの行数が他のファイルと異なる場合、出力はおそらく使用できなくなります。
#!/usr/bin/Perl
use strict;
my @csv=();
foreach (@ARGV) {
my $linenum=0;
open(F,"<",$_) or die "couldn't open $_ for read: $!\n";
while (<F>) {
chomp;
$csv[$linenum++] .= "," . $_;
};
close(F);
};
foreach (@csv) {
s/^,//; # strip leading comma from line
print $_,"\n";
};
次の入力ファイルがあるとします。
==> 1.csv <==
1,2,3,4
1,2,3,4
1,2,3,4
1,2,3,4
==> 2.csv <==
5,6,7,8
5,6,7,8
5,6,7,8
5,6,7,8
==> 3.csv <==
9,10,11,12
9,10,11,12
9,10,11,12
9,10,11,12
次の出力が生成されます。
$ ./mergecsv.pl *.csv
1,2,3,4,5,6,7,8,9,10,11,12
1,2,3,4,5,6,7,8,9,10,11,12
1,2,3,4,5,6,7,8,9,10,11,12
1,2,3,4,5,6,7,8,9,10,11,12
ここまで読んだので、paste -d, *.csv
が実行しないことは何も実行しないことを認めましょう。では、なぜperlに悩むのでしょうか。 paste
は非常に柔軟性がありません。データがpaste
の動作に完全に一致している場合は問題ありません。これは、作業に最適で非常に高速です。そうでなければ、それはあなたにとって完全に役に立たない。
このようなPerlスクリプトを改善する方法はいくつもあります(たとえば、各ファイルのフィールド数をカウントし、各ファイルの@csv
に空のフィールドの正しい数を追加することにより、異なる長さのファイルを処理します( s)行が欠落している、または少なくとも異なる長さを検出してエラーで終了する)が、より高度なマージが必要な場合、これは妥当な出発点です。
ところで、これは非常に単純なアルゴリズムを使用し、すべての入力ファイルの内容全体をメモリ(@csv
内)に一度に格納します。最新のシステムでそれぞれ数MBまでのファイルの場合、それは不当なことではありません。ただし、巨大な.csvファイルを処理している場合、より良いアルゴリズムは次のようになります。
それを達成するための最も簡単なアプローチは、次のコマンドを入力することです
cat *csv > combined.csv
このファイルには、あなたが言及した方法で、すべてのcsvファイルの内容が含まれます。
awk '(NR == 1) || (FNR > 1)' *.csv > 1000Plus5years_companies_data.csv