LINUX.ORG.RU

Поиск файлов по pcre regexp

 , ,


0

1

Привет

Посоветуйте, пожалуйста, модуль для perl, для поиска файлов по pcre регулярному выражению. То есть типа

perl -E 'say join "\t", glob "/etc/*"'
, но с обычными perl-регекспами, а не этими убогими wildcard.

Или посоветуйте как написать его, так, чтобы при поиске например по регекспу '/etc/nginx/\w+\.conf' он открывал только нужные директории, и не ходил, например в /var? Можно конечно пилить регулярку по слешам, и проверять похоже ли эта часть на регексп, но это ограниченно.

В итоге хочется получать список файлов, заданный указанным в конфиге регекспом, не сканируя все имена на совпадение этому регекспу.

★★★

Последнее исправление: disarmer (всего исправлений: 1)

File::List видел, но он проверяет все файлы. К тому же, возвращает списком, а не итератором, а это может занять дофига памяти

disarmer ★★★
() автор топика
Ответ на: комментарий от gh0stwizard

File::Find то каким боком? искать все файлы в корне и сравнивать с regexpом? Зачем мне тысячи ненужных сравнений, если по регекспу уже видно, что файлы лежат например в /etc.

File::Find::Rule просто чуть более объектно ориентированый фронтенд к File::Find. Он тоже будет обходить всё дерево, не пытаясь вдуматься в регексп

disarmer ★★★
() автор топика

Может, лучше руками указать где ему можно искать? Имхо, тут умный механизм будет лишним потому что примитивный вариант легко надурить, а «умный» подход городить, имхо, не так просто написать.

Ну или надо обозначить какие regex-правила допустимы на вход функции.

true_admin ★★★★★
()
Ответ на: комментарий от true_admin

хочется в конфиге описывать, а не в коде. Пока склоняюсь к варианту, чтобы указывать частями, тогда не придётся резать путь по слешам. Вроде такого:

path1=>['/etc/nginx/',qr'\w+\.conf'],
path2=>['/var/log/',qr'.*','access.log']
Тут вполне ясно можно определить где статический путь, а где регексп. Вполне алгоритм вырисовывается, просто я удивлён, что этого уже нет в модулях

disarmer ★★★
() автор топика

Посоветуйте, пожалуйста, модуль для perl, для поиска файлов по pcre регулярному выражению.

find(1)

В итоге хочется получать список файлов, заданный указанным в конфиге регекспом, не сканируя все имена на совпадение этому регекспу.

NoWay

emulek
()
Ответ на: комментарий от disarmer

Зачем мне тысячи ненужных сравнений, если по регекспу уже видно, что файлы лежат например в /etc.

а разве каталог для поиска только корень, и всё? AFAIK директория задаётся отдельно.

emulek
()
Ответ на: комментарий от disarmer

Ээээ. Вы не понимаете как работает фс и как происходит поиск файлов. Зачем нужно начинать с корня? Начинайте с /etc. И прочитайте ман по glob(), он делает ровным счетом тоже самое. Также грузит весь список файлов, также после делает сравнение. То, что можно указать путь внутри регепса нифига не значит!

gh0stwizard ★★★★★
()
Ответ на: комментарий от disarmer

Чего нет в модулях? Регепс это регепс. Путь это путь. Епрст, да прочтите примеры для File::Find!!!

gh0stwizard ★★★★★
()
Ответ на: комментарий от gh0stwizard

ok, я хочу найти все файлы по маске «^/.i./.*\.so$». В FHS под это условие попадают только файлы в директориях /bin и /lib. Зачем мне вообще проверять файлы, например в /usr, если они заведомо не подходят?

disarmer ★★★
() автор топика
Ответ на: комментарий от disarmer

А теперь с тем же условием найди файлы на макоси. Что ты сделаешь? Верно получишь список директорий корня. Или на винде, пусть диск по умолчанию «C:», но тут нет ни lib, ни bin. Вообще нихера нет. Компьютер делает то, что говорят. И твое условие-регепс говорит: фигачь от корня. А если ты явно скажешь ищи в /bin, в /etc, то это даст другие результаты вне зависимости от ОС. На линухе найдет, на маке в /lib может и найдет что, для /bin выкинет ошибку; и на винде в обоих случаях выкинет ошибку.

Вобщем твоя задача «телепата» делается одной функцией, которая сначала берет регепс как текстовую строку, дальше пытается сопоставить с известными/просканированными/списком директорий. После вырезает ее, подсовывает в find(или аналог) как часть пути, дальше ищет по регепсу для файлов/директорий. При необходимости сделать н-рекурсий.

И это должен делать ты. Написать говно-функцию такую может почти каждый. Написать такую функцию без изъянов и эксплойтов, а также туевой тучой правил как писать запрос — не каждый и не каждому понравиться, что надо экранировать дофига символов.

gh0stwizard ★★★★★
()
Ответ на: комментарий от gh0stwizard

Про совместимость я ничего не говорил, у меня скрипт завязан на *nix(системный мониторинг).

Уже кое-что накостылял, вполне ищет так:

Режем регексп по '/', сохраняем в массив вида:

   /var
   /var/log
   /var/log/pacman\..*
Потом перебираем файлы с помощью file::find, для каждого находим количество слешей, и сравниваем с соответсвующим элементом массива. Несоответствующие директории исключаем из дальнейшего обхода. Несмотря на громоздкость, работает значительно быстрее чем полный обход.

Пока вижу проблему в том, что часть регекспа может соответствовать нескольким директориям подряд, вроде

   /var/.*/[a-z]\.log
должен соответствовать всем файлам логов в /var, а не только в директориях второго уровня вложенности. Думаю это решаемая проблема.

disarmer ★★★
() автор топика

find2perl

$ find2perl / -name «\w+\d\.\d+»

#! /usr/bin/perl -w
    eval 'exec /usr/bin/perl -S $0 ${1+"$@"}'
        if 0; #$running_under_some_shell

use strict;
use File::Find ();

# Set the variable $File::Find::dont_use_nlink if you're using AFS,
# since AFS cheats.

# for the convenience of &wanted calls, including -eval statements:
use vars qw/*name *dir *prune/;
*name   = *File::Find::name;
*dir    = *File::Find::dir;
*prune  = *File::Find::prune;

sub wanted;



# Traverse desired filesystems
File::Find::find({wanted => \&wanted}, '/');
exit;


sub wanted {
    /^\w\+\d\\.\d\+\z/s
    && print("$name\n");
}

joy4eg ★★★★★
()
Ответ на: find2perl от joy4eg

Спасибо, я умею пользоваться File::Find.

Проблема глубже, сложно сказать заранее, сматчится ли строка по регулярному выражению, имея только часть строки (неполный путь). По крайней мере, не повторяя движок регулярных выражений самому.

disarmer ★★★
() автор топика
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.