Показать файлы для size с нижней и верхней границей без использования `find`

awk 'FNR == 1 { f1=f2=f3=0; };

     /one/   { f1++ };
     /two/   { f2++ };
     /three/ { f3++ };

     f1 && f2 && f3 {
       print FILENAME;
       nextfile;
     }' *

Если вы хотите автоматически обрабатывать файлы с gzip-сжатием, либо запустите это в цикле с zcat (медленно и неэффективно, потому что вы будете разветвлять awk много раз в цикле, один раз для каждого имени файла) или перепишите тот же алгоритм в perl и используйте библиотечный модуль IO :: Uncompress :: AnyUncompress , который может распаковывать несколько различных типов сжатых файлов (gzip, zip, bzip2 , lzop). или в python, в котором также есть модули для обработки сжатых файлов.


Вот версия perl , которая использует IO :: Uncompress :: AnyUncompress , чтобы разрешить любое количество шаблонов и любое количество имен файлов (содержащих простой текст или сжатый текст).

Все аргументы до - обрабатываются как шаблоны поиска. Все аргументы после - рассматриваются как имена файлов. Примитивная, но эффективная обработка опций для этой работы. Лучшая обработка параметров (например, поддержка параметра -i для поиска без учета регистра) может быть достигнута с помощью модулей Getopt :: Std или Getopt :: Long . .

Запустите его так:

$ ./arekolek.pl one two three -- *.gz *.txt
1.txt.gz
4.txt.gz
5.txt.gz
1.txt
4.txt
5.txt

(Я не буду перечислять здесь файлы {1..6} .txt.gz и {1..6} .txt ... они просто содержат некоторые или все слова "один" "два" "три" "четыре" "пять" и "шесть" для тестирования. Файлы, перечисленные в выходных данных выше, ДОЛЖНЫ содержать все три шаблона поиска.Проверьте это самостоятельно на своих данных)

#! /usr/bin/perl

use strict;
use warnings;
use IO::Uncompress::AnyUncompress qw(anyuncompress $AnyUncompressError) ;

my %patterns=();
my @filenames=();
my $fileargs=0;

# all args before '--' are search patterns, all args after '--' are
# filenames
foreach (@ARGV) {
  if ($_ eq '--') { $fileargs++ ; next };

  if ($fileargs) {
    push @filenames, $_;
  } else {
    $patterns{$_}=1;
  };
};

my $pattern=join('|',keys %patterns);
$pattern=qr($pattern);
my $p_string=join('',sort keys %patterns);

foreach my $f (@filenames) {
  #my $lc=0;
  my %s = ();
  my $z = new IO::Uncompress::AnyUncompress($f)
    or die "IO::Uncompress::AnyUncompress failed: $AnyUncompressError\n";

  while ($_ = $z->getline) {
    #last if ($lc++ > 100);
    my @matches=( m/($pattern)/og);
    next unless (@matches);

    map { $s{$_}=1 } @matches;
    my $m_string=join('',sort keys %s);

    if ($m_string eq $p_string) {
      print "$f\n" ;
      last;
    }
  }
}

Хэш % шаблонов содержит полный набор шаблонов, которые файлы должны содержать хотя бы по одному из каждого члена $ _ pstring - строка, содержащая отсортированные ключи этого хэша. Строка $ pattern содержит предварительно скомпилированное регулярное выражение, также построенное из хэша % patterns .

$ pattern сравнивается с каждой строкой каждого входного файла (с использованием модификатора / o для компиляции $ pattern только один раз, поскольку мы знаем, что он никогда не изменится во время выполнения), а map () используется для построения хэша (% s), содержащего совпадения для каждого файла.

Всякий раз, когда все шаблоны были замечены в текущем файле (путем сравнения if $ m_string (отсортированные ключи в % s ) равны $ p_string ]), напечатайте имя файла и перейдите к следующему файлу.

Это не особенно быстрое решение, но оно не является необоснованно медленным. Первая версия занимала 4 минуты 58 секунд на поиск трех слов в сжатых файлах журнала объемом 74 МБ (всего 937 МБ без сжатия). Текущая версия занимает 1 мин. 13 сек. Вероятно, можно было бы сделать дальнейшую оптимизацию.

Одна очевидная оптимизация заключается в использовании этого вместе с xargs -P aka - max-procs для выполнения нескольких поисков по подмножествам файлы параллельно. Для этого вам нужно подсчитать количество файлов и разделить на количество ядер / процессоров / потоков, которые есть в вашей системе (и округлить, добавив 1). напримерв моем наборе образцов выполнялся поиск 269 файлов, а в моей системе 6 ядер (AMD 1090T), поэтому:

patterns=(one two three)
searchpath='/var/log/apache2/'
cores=6
filecount=$(find "$searchpath" -type f -name 'access.*' | wc -l)
filespercore=$((filecount / cores + 1))

find "$searchpath" -type f -print0 | 
  xargs -0r -n "$filespercore" -P "$cores" ./arekolek.pl "${patterns[@]}" --

При такой оптимизации потребовалось всего 23 секунды, чтобы найти все 18 совпадающих файлов. Конечно, то же самое можно сделать и с любым другим решением. ПРИМЕЧАНИЕ. Порядок имен файлов, перечисленных в выходных данных, будет другим, поэтому, возможно, впоследствии потребуется их сортировка, если это имеет значение.

Как отмечает @arekolek, несколько zgrep с find -exec или xargs могут сделать это значительно быстрее, но этот сценарий имеет то преимущество, что поддерживает любое количество шаблонов для поиска и может работать с несколькими различными типами сжатия.

Если сценарий ограничен проверкой только первых 100 строк каждого файла, он проходит все из них (в моем образце размером 74 МБ из 269 файлов) за 0,6 секунды. Если это полезно в некоторых случаях, его можно преобразовать в параметр командной строки (например, -l 100 ), но при этом существует риск не найти всех совпадающих файлов.


Кстати, согласно странице руководства для IO :: Uncompress :: AnyUncompress , поддерживаются следующие форматы сжатия:


Последняя (надеюсь) оптимизация. Используя модуль PerlIO :: gzip (упакованный в debian как libperlio-gzip-perl ) вместо IO :: Uncompress :: AnyUncompress , я получил время примерно до 3.1 секунда для обработки моих 74 МБ файлов журнала. Были также некоторые небольшие улучшения за счет использования простого хеша вместо Set :: Scalar (что также позволило сэкономить несколько секунд с версией IO :: Uncompress :: AnyUncompress ).

PerlIO :: gzip был рекомендован как самый быстрый perl gunzip в https: // stackoverflow.com / a / 1539271/137158 (найдено с помощью поиска в Google по запросу perl fast gzip распаковать )

Использование xargs -P с этим нисколько не улучшило его . Фактически, казалось, что это даже замедлило его где-то от 0,1 до 0,7 секунды. (Я пробовал четыре запуска, и моя система выполняет другие функции в фоновом режиме, которые изменяют время)

Цена в том, что эта версия скрипта может обрабатывать только файлы, сжатые и сжатые в формате gzip. Скорость против гибкости: 3,1 секунды для этой версии против 23 секунд для версии IO :: Uncompress :: AnyUncompress с оболочкой xargs -P (или 1 мин. 13 с без xargs -P ).

#! /usr/bin/perl

use strict;
use warnings;
use PerlIO::gzip;

my %patterns=();
my @filenames=();
my $fileargs=0;

# all args before '--' are search patterns, all args after '--' are
# filenames
foreach (@ARGV) {
  if ($_ eq '--') { $fileargs++ ; next };

  if ($fileargs) {
    push @filenames, $_;
  } else {
    $patterns{$_}=1;
  };
};

my $pattern=join('|',keys %patterns);
$pattern=qr($pattern);
my $p_string=join('',sort keys %patterns);

foreach my $f (@filenames) {
  open(F, "<:gzip(autopop)", $f) or die "couldn't open $f: $!\n";
  #my $lc=0;
  my %s = ();
  while () {
    #last if ($lc++ > 100);
    my @matches=(m/($pattern)/ogi);
    next unless (@matches);

    map { $s{$_}=1 } @matches;
    my $m_string=join('',sort keys %s);

    if ($m_string eq $p_string) {
      print "$f\n" ;
      close(F);
      last;
    }
  }
}
2
09.05.2016, 14:05
0 ответов

Теги

Похожие вопросы