我需要多個文件中每行的第二個字段。 '減'不 工作,因爲一些行有前導空格。
perl -anle 'print $F[1]' *manyfiles* > result
確實工作,但速度很慢。
有沒有更快的方法來做到這一點?
我需要多個文件中每行的第二個字段。 '減'不 工作,因爲一些行有前導空格。
perl -anle 'print $F[1]' *manyfiles* > result
確實工作,但速度很慢。
有沒有更快的方法來做到這一點?
awk '{print $2}' files ... > result
可能會更快。
在使用剪切腳本之前,您是否可以不使用sed刪除前導空格?
例如: sed -e 's/^[ \t]*//'
將產生一個文件流沒有前導空格。只需將其輸入到腳本中即可。
我猜測autosplit模式很慢,因爲通過分割線獲得的整個數組必須存儲在內存中。如果你的文件排隊很長,這尤其相關。這個怎麼樣:
perl -ne 'print $1, "\n" if m/^\s*\S+\s+(\S+)/'
在這裏我們不處理超過第二字線的一部分。當您使用index
和substr
代替正則表達式時,您還可以測試性能。
['unpack'](http://p3rl.org/unpack)。 – daxim 2012-04-08 15:00:10
的Perl:
perl -ne 'print "$1\n" if m/\s*\S+\s+(\S+)/' manyfiles >result
非的Perl:
awk '{print $2}' manyfiles >result
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;
我跑上面10個文件,每個1_000_000線的腳本。在每個文件中,20%的行有一些主要的空白。詳情請參閱Can Parallel::ForkManager speed up a seemingly IO bound task?。
# sync # echo 3 > /proc/sys/vm/drop_caches $ /usr/bin/time -f '%Uuser %Ssystem %Eelapsed %PCPU' ./process.pl 1 > output 24.44user 0.93system 0:29.08elapsed 87%CPU $ rm output # sync # echo 3 > /proc/sys/vm/drop_caches $ /usr/bin/time -f '%Uuser %Ssystem %Eelapsed %PCPU' ./process.pl 2 > output 24.95user 0.91system 0:18.31elapsed 141%CPU $ rm output # sync # echo 3 > /proc/sys/vm/drop_caches $ /usr/bin/time -f '%Uuser %Ssystem %Eelapsed %PCPU' ./process.pl 4 > output 24.70user 0.88system 0:17.45elapsed 146%CPU $ rm output # sync # echo 3 > /proc/sys/vm/drop_caches $ /usr/bin/time -f '%Uuser %Ssystem %Eelapsed %PCPU' ./process.pl 1 > output 25.31user 0.95system 0:29.72elapsed 88%CPU
因此,在我看來,利用所有核心都有一定的收益。
我沒有嘗試任何其他建議,看看使用Perl + Parallel::ForkManager比其中任何一個更好。
這種方法的一個明顯的缺點是它會交錯源文件中的行。這在你的特定情況下可能並不重要。
我想知道這個問題有多大是IO界限(這意味着分叉可能沒有那麼大的幫助)。 – 2012-04-11 11:22:26
@briandfoy我在老化的雙核筆記本電腦上做了一個測試。在Windows中,腳本的修正版本在兩個進程中大約60%的時間運行,而單個運行10個文件時各有1,000,000行(每個文件中大約20%的行都有前導空格)。我將啓動到Linux並在那裏嘗試。不同之處似乎在於任務管理器的CPU利用率,顯示兩個進程都使用100%的內核。在Linux上嘗試此操作後,我會發佈一個更正的腳本和結果。 – 2012-04-11 13:00:02
@briandfoy似乎確實有利於利用所有可用的內核。看到我更新的答案。 – 2012-04-11 14:46:06
如果下面是不夠好,
perl -nE'say /^\s*\S+\s+(\S+)/' *
我想嘗試
perl -ple's/^\s+//' * | cut
如果這不是一次性的事情,速度真的很重要,你可以寫一個在C中用小修剪工具取代上面的perl
。
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」只是舉例面膜,會更加更快,如果你不會使用它)
我想爲這些解決方案添加一些數字。 aaqp.txt文件是130 MB和1,000,000行,平均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已經花費時間去除前導空格,那麼運行sed也只會佔用更多的CPU時間。即使在離散核心上運行sed和Perl,管道開銷可能也很明顯。 – ctt 2012-04-07 17:32:05