![]() |
|
Модераторы: korob2001, ginnie |
![]()
|
|
| ramus |
|
||||||
|
Шустрый ![]() Профиль Группа: Участник Сообщений: 53 Регистрация: 21.2.2008 Репутация: 1 Всего: 1 |
Есть скрипт на shell который читает конфигурационный файл со строками вида
MV /path/to/SRC/dir /path/to/DEST/dir select_CU и в данном случае переносит файлы удовлетворяющие условию выборки select_CU из директории /path/to/SRC/dir в директорию /path/to/DEST/dir правила описаны в файле правил: (для данного примера)
этот shell запускается из cron раз в 5 минут. Проблема в том, что когда записей в конфигурационном файле стало более 1000, то время работы скрипта составляет более минуты. Естественно я взялся переписать все это на перл. И тут возник идеологический вопрос: Нужно описать правило отбора файлов в директории (думаю без регулярки не обойтись). Надо наиболее универсально, но чтобы читаемо и просто. Если условие ИЛИ регулярным выражением описывается легко, то условие И не понятно как. например для приведенного выше примера (отобрать все файлы начинающиеся на С или U или с или u)
(?i) - ignore case но как написать что при этом НЕ заканчивающиеся на *.in_progress ? Ограничение: в основном коде будет что то типа if $_ =~ m/${select_CU}/ и поэтому все условие должно содержаться в select_CU Либо так сделать нельзя и что тогда делать? какие варианты? либо ткните в доку, но чесслово не нашел как :( к сожалению в реальной жизни все сложнее, есть например такие
как такое переписать (если не знакома команда grep, то отобрать все файлы игнорируя регистр начинающиеся на R или E или G или W у которых начиная со второй буквы в имени файла будет 001000 или 100 или 101 или 103 ... И не заканчивающиеся на .in_progress |
||||||
|
|||||||
| tolkien |
|
|||
|
Опытный ![]() ![]() Профиль Группа: Участник Сообщений: 277 Регистрация: 5.4.2008 Репутация: 4 Всего: 4 |
Если вы хотите переписать этот код на PERL и вместо grep использовать регулярные выражения PERL.
Тогда вам надо будет поменять формат записи условий в select_CU писать по другому. select_CU="grep -ie ^C -e ^U | grep -iv '[.]in_progress$'" здесь выполняються последовательно два grep grep -ie ^C -e ^U grep -iv '[.]in_progress$'" на PERL /^[cCuU]/ /\.n_progress$/ надо придумать свой разделитель между разными рег. выраж. Например такой ### select_CU=^[cCuU]###/\.n_progress$/ потом в коде написать так @re = split(/###/, select_CU) и последовательно выполнить каждое рег выражение foreach my $re (@re) { if ($_ =~ m/$re/) { } } select_APL_LOG="grep -ie ^R -ie ^E -ie ^G -ie ^W | grep -e '^.001000.*' -e '^.100.*' -e '^.101.*' \ -e '^.103.*' -e '^.105.*' -e '^.106.*' -e '^.107.*' -e '^.108.*' \ -e '^.123.*' | grep -iv [.]in_progress$ " это переписывается так же как выше написано Это сообщение отредактировал(а) tolkien - 23.4.2008, 03:22 |
|||
|
||||
| amg |
|
||||
|
Эксперт ![]() ![]() ![]() Профиль Группа: Завсегдатай Сообщений: 1145 Регистрация: 3.8.2006 Где: Новосибирск Репутация: 38 Всего: 50 |
|
||||
|
|||||
| amg |
|
|||
|
Эксперт ![]() ![]() ![]() Профиль Группа: Завсегдатай Сообщений: 1145 Регистрация: 3.8.2006 Где: Новосибирск Репутация: 38 Всего: 50 |
Сам скрипт мог бы выглядеть как то так (но я его не проверял!):
Это сообщение отредактировал(а) amg - 23.4.2008, 07:30 |
|||
|
||||
| ramus |
|
||||||
|
Шустрый ![]() Профиль Группа: Участник Сообщений: 53 Регистрация: 21.2.2008 Репутация: 1 Всего: 1 |
2 tolkien
Да, интересная мысль. Главное просто и универсально. Попробую. Спасибо Вам. И с точки зрения производительности хорошо - при первом совпадении не надо проверять все оставшиеся варианты. 2 amq стараюсь внимательно читать Ваши посты - так как Вы пишете емко, но с минимумом комментариев. Многие решения нестандартны и интересны. Чувствуется большой опыт программирования. Естественно, то что Вы пишете Вам очевидно. Я с перл только начинаю дружить, поэтому без комментариев сложновато. Правильно я понял, что в регулярном выражении $select_APL_LOG = '(?!.*\.in_progress$)^(?i:[REGW])(?:001000|10[013])'; ?! - отрицание ?: - не захватывать () в $1 ? но вот сами три шаблона в скобках как работают не понятно
выводит Yes как и должно быть в кэмелбук таких примеров я не нашел...скорее плохо искал (все таки >1000стр.) там есть типа /^(regw).*out$/ . то есть в скобках m// один шаблон, а тут три . Они так объединяются по условию И ?
пока мой опыт переписывания shell скриптов (около десятка) на перл говорит, что перл рулит |
||||||
|
|||||||
| ramus |
|
||||||
|
Шустрый ![]() Профиль Группа: Участник Сообщений: 53 Регистрация: 21.2.2008 Репутация: 1 Всего: 1 |
пространные рассуждения удалил
для того, чтобы подгрузить процедуры и переменные из другого файла, надо сделать так файл mover.rules
основной файл
если запустить то выводит
Это сообщение отредактировал(а) ramus - 24.4.2008, 18:41 |
||||||
|
|||||||
| amg |
|
|||
|
Эксперт ![]() ![]() ![]() Профиль Группа: Завсегдатай Сообщений: 1145 Регистрация: 3.8.2006 Где: Новосибирск Репутация: 38 Всего: 50 |
Описание того, как вставлять различные логические условия в регулярное выражение, есть, например, в Perl Cookbook (с. 254 в переводе 2-го издания). Но пользоваться этим нужно лишь в исключительных случаях. Даже элементарное /a|b/ лучше заменять на /a/ || /b/ - как правило, быстрее будет работать, а для более сложных случаев (типа того, что ниже) - будет еще и гораздо понятнее.
(? (?!) - не просто отрицание, а "отрицательное" заглядывание вперед. Приведенное регулярное выражение пробегает по всем символам строки и смотрит, во-первых, чтобы строка начиналась на (?i:[REGW])(?:001000|10[013] и, во-вторых, чтобы перед каждым символом не было подстроки, оканчивающейся на \.in_progress. Понятно, что пока конец строки не достигнут, второе условие будет выполняться. Но когда встали на конец строки, тут то и появляется возможность определить, есть ли перед ним "подстрока, оканчивающаяся на \.in_progress". Естественно, такую извращенную логику я не сам придумал и реализовал - подсмотрел в Perl Cookbook |
|||
|
||||
| ramus |
|
||||
|
Шустрый ![]() Профиль Группа: Участник Сообщений: 53 Регистрация: 21.2.2008 Репутация: 1 Всего: 1 |
Значит предложение tolkien (разбивать на несколько логических правил и последовательно выполнить каждое рег выражение) для данного случая подходит лучше. Кстати
например для двух правил по И select_CU=^[cCuU]#AND#/\.n_progress$/ для двух правил по ИЛИ select_CU=^[cCuU]#OR#/\.n_progress$/ но только как бы не нарваться на совпадение с самим шаблоном и необходимо придумать правило с приоритетами ( например в каком порядке выполнять 1 AND 2 OR 3 )? в общем направление решения мне понятно, буду реализовывать спасибо за разъяснения по RE за ссылку спасибо, почитаю |
||||
|
|||||
| arto |
|
|||
|
Эксперт ![]() ![]() ![]() Профиль Группа: Завсегдатай Сообщений: 1495 Регистрация: 31.10.2004 Репутация: 38 Всего: 40 |
а циферки привести можно? а то у меня: # perl -MBenchmark=timethese -de0 DB<1> @a = map { join "",map { qw(a b)[int rand 2] } 3..int(rand 10) } 1..102400 DB<2> timethese (10_000,{ 'A' => sub { my $a; foreach (@a) { $a += m#^a|^b# } return $a },'B' => sub { my $a; foreach (@a) { $a += m#^(?:a|b)# } return $a },'C' => sub { my $a; foreach (@a) { $a += m#^a# || m#^b# } return $a; } }) Benchmark: timing 10000 iterations of A, B, C... A: 705 wallclock secs (658.01 usr + 4.76 sys = 662.77 CPU) @ 15.09/s (n=10000) B: 683 wallclock secs (638.36 usr + 4.50 sys = 642.86 CPU) @ 15.56/s (n=10000) C: 795 wallclock secs (739.54 usr + 5.09 sys = 744.63 CPU) @ 13.43/s (n=10000) |
|||
|
||||
| amg |
|
||||
|
Эксперт ![]() ![]() ![]() Профиль Группа: Завсегдатай Сообщений: 1145 Регистрация: 3.8.2006 Где: Новосибирск Репутация: 38 Всего: 50 |
Я не очень понял, зачем это надо. Почему это не может быть нативный перловский код?
mover.rules:
скрипт:
|
||||
|
|||||
| amg |
|
||||||
|
Эксперт ![]() ![]() ![]() Профиль Группа: Завсегдатай Сообщений: 1145 Регистрация: 3.8.2006 Где: Новосибирск Репутация: 38 Всего: 50 |
Пожалуйста.
arto, просто Вы обнаружили тот самый случай, который не подпадает под оговорку "как правило". У Вас регулярное выражение способно уже на первом символе строки решить, "Да" или "Нет". В моем же случае для этого решения ему нужно просмотреть всю весьма длинную строку до конца. Думаю, в моем случае результат сравнения будет совсем катастофическим, если для большого количества моделей воспользоваться приемом, который многие любят использовать:
|
||||||
|
|||||||
| ramus |
|
||||||
|
Шустрый ![]() Профиль Группа: Участник Сообщений: 53 Регистрация: 21.2.2008 Репутация: 1 Всего: 1 |
И пример красивый привели. Действительно перловый стиль. А я все шеллом мыслю :( С правилами отбора все ясно и просто Теперь думаю все ли случаи позволит реализовать предложенный Вами подход в "actions":
так как реально actions бывают весьма извращенны например такие два примера actions на шелле
требуемая бизнес логика бывает весьма извращенна |
||||||
|
|||||||
| ramus |
|
||||||||||||||||
|
Шустрый ![]() Профиль Группа: Участник Сообщений: 53 Регистрация: 21.2.2008 Репутация: 1 Всего: 1 |
Блин
есть файл правил (file_rules). В нем могут определяться абсолютно любые (отвечающие синтаксису перла) переменные и процедуры. ВАЖНО: Их имена в основной проге заранее неизвестны. Например:
Он зачитывается из основной проги как
Есть конфигурационный файл, в котором эти переменные и процедуры могут использоваться. Например
надо: из проги на перле, зачитав из конфигурационного файла строку, правильно ее разобрать. Например в данном случае строка:
должна быть оттранслирована в (если дата запуска проги 3 мая 2008)
пытаюсь сделать через eval
Error: while eval= - Illegal division by zero at (eval 4) line 1. тогда пытаюсь так (через выполнение регулярки /e )
ругается что
а я не могу написать в основной проге our $disk_T, так как я формально до ее запуска не знаю какие переменные навставляют в file_rules. Что сделать - ума не приложу не хотелось бы весь файл правил построчно проверять на наличие переменных и делать "our переменная", так как тогда надо разбирать что переменная объявляется не внутри процедур, а это совсем другое решение :( сделать два отдельных файла правил - для процедур и для переменных что то не хочется |
||||||||||||||||
|
|||||||||||||||||
| ramus |
|
||||
|
Шустрый ![]() Профиль Группа: Участник Сообщений: 53 Регистрация: 21.2.2008 Репутация: 1 Всего: 1 |
Вроде разобрался. Перед строкой
надо дать
|
||||
|
|||||
| amg |
|
|||
|
Эксперт ![]() ![]() ![]() Профиль Группа: Завсегдатай Сообщений: 1145 Регистрация: 3.8.2006 Где: Новосибирск Репутация: 38 Всего: 50 |
||||
|
||||
![]()
|
| Правила форума "Perl" | |
|
|
Если Вам понравилась атмосфера форума, заходите к нам чаще! С уважением, korob2001, sharq. |
| 0 Пользователей читают эту тему (0 Гостей и 0 Скрытых Пользователей) | |
| 0 Пользователей: | |
| « Предыдущая тема | Perl: Общие вопросы | Следующая тема » |
|
|
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности Powered by Invision Power Board(R) 1.3 © 2003 IPS, Inc. |