複数のファイルのすべての行の 2 番目のフィールドが必要です。一部の行の先頭にスペースがあるため、「カット」は機能しません。
perl -anle 'print $F[1]' *manyfiles* > result
動作しますが、遅いです。
これを行うための大幅に高速な方法はありますか?
複数のファイルのすべての行の 2 番目のフィールドが必要です。一部の行の先頭にスペースがあるため、「カット」は機能しません。
perl -anle 'print $F[1]' *manyfiles* > result
動作しますが、遅いです。
これを行うための大幅に高速な方法はありますか?
awk '{print $2}' files ... > result
より速いかもしれません。
カットスクリプトを使用する前に、先頭のスペースを sed で削除できませんでしたか?
たとえば
sed -e 's/^[ \t]*//'
、先頭にスペースがないファイルでストリームを生成します。これをスクリプトにパイプするだけです。
sed -rn 's/\s*[^\s]+\s+([^\s]+).*/\1/p' file1 file2 > parsed_text
より速くする必要があります。
または、これを使用してファイルのリストを作成できます。
find /path/to/files/ -type f -iname "*" -print0 | xargs -0 -I {} sed …
(たとえば、マスクの「iname」は、使用しない場合はより高速になります)
Parallel :: ForkManagerは、特に出力をソースファイルごとにグループ化する必要がない場合に役立つことがあります。ただし、ディスクに同時にアクセスするプロセスの数を増やすと、速度が低下する可能性もありますが、一見の価値があります。
次の例は、Parallel::ForkManager
マニュアルページから採用されています(以前のバージョンに存在する明らかなエラーは修正されています)。
#!/usr/bin/env perl
use strict; use warnings;
use Parallel::ForkManager;
my ($maxproc) = @ARGV;
my @files = ('01' .. '10');
my $pm = Parallel::ForkManager->new($maxproc);
for my $file (@files) {
my $pid = $pm->start and next;
my $ret = open my $h, '<', $file;
unless ($ret) {
warn "Cannot open '$file': $!";
$pm->finish;
}
while (my $line = <$h>) {
next unless $line =~ /^\s*\S+\s+(\S+)/;
print "$1\n";
}
$pm->finish;
}
$pm->wait_all_children;
上記のスクリプトを、それぞれ1_000_000行の10個のファイルで実行しました。各ファイルでは、行の20%に先頭の空白があります。Parallel :: ForkManagerは、一見IOバウンドのタスクを高速化できますか?を参照してください。詳細については。
#同期 #echo 3> / proc / sys / vm / drop_caches $ / usr / bin / time -f'%Uuser%Ssystem%Eelapsed%PCPU'./process.pl1>出力 24.44user 0.93system 0:29.08経過87%CPU $rm出力 #同期 #echo 3> / proc / sys / vm / drop_caches $ / usr / bin / time -f'%Uuser%Ssystem%Eelapsed%PCPU'./process.pl2>出力 24.95user 0.91system 0:18.31経過141%CPU $rm出力 #同期 #echo 3> / proc / sys / vm / drop_caches $ / usr / bin / time -f'%Uuser%Ssystem%Eelapsed%PCPU'./process.pl4>出力 24.70user 0.88system 0:17.45経過146%CPU $rm出力 #同期 #echo 3> / proc / sys / vm / drop_caches $ / usr / bin / time -f'%Uuser%Ssystem%Eelapsed%PCPU'./process.pl1>出力 25.31user 0.95system 0:29.72経過88%CPU
ですから、すべてのコアを利用することで、いくらかの利益があるように思えます。
私は、Perl + Parallel::ForkManagerの使用がそれらのいずれよりも優れているかどうかを確認するために与えられた他の提案のいずれも試しませんでした。
この方法の明らかな欠点の1つは、ソースファイルからの行をインターリーブすることです。これは、特定の状況では問題になる場合と問題にならない場合があります。
これらのソリューションにいくつかの数字を入れたかったのです。aaqp.txtファイルは 130 MB で、1,000,000 行あり、1 行あたり平均 7 フィールドです。このために実際に 50 GB 以上のサンプル データを生成しましたが、これらのいずれかが完了するのを待つのが待ちきれませんでした。
$ time perl -anle 'print $F[1]' aaqg.txt > result
real 0m18.526s
user 0m18.368s
sys 0m0.089s
$ time awk '{print $2}' aaqg.txt > result
real 0m4.051s
user 0m3.592s
sys 0m0.091s
$ time perl -nE 'say $1 if m/\s*\S+\s+(\S+)/' aaqg.txt > result
real 0m2.009s
user 0m1.901s
sys 0m0.066s
$ time perl -nE'say /^\s*\S+\s+(\S+)/' aaqg.txt > result
real 0m2.069s
user 0m1.813s
sys 0m0.069s
パール:
perl -ne 'print "$1\n" if m/\s*\S+\s+(\S+)/' manyfiles >result
非 Perl:
awk '{print $2}' manyfiles >result
以下が不十分な場合は、
perl -nE'say /^\s*\S+\s+(\S+)/' *
やってみます
perl -ple's/^\s+//' * | cut
これが 1 回限りのことではなく、速度が本当に重要な場合は、C で小さなトリミング ツールを記述してperl
、上記を置き換えることができます。