Быстрая очистка каталога с помощью Perl

Мне нужно очистить каталог с миллионами файлов журналов на моем веб-сервере. И я нашел эту замечательную статью о том, как это сделать. Однако в этой строчке есть пара интересных вещей, которые меня интересуют.

Вот интересующий меня код Perl:

for(<*>){((stat)[9]<(unlink))}

Работал с perl -e 'code'.

Итак, вот мои вопросы:

  1. конструкция for(<*>) - я предполагаю, что она перебирает файлы в текущем каталоге. Но где он хранит итератор?
  2. я предполагаю, что функции stat и unlink ожидают как минимум один аргумент... Но где он?
  3. почему результат вызова (stat)[9] сравнивается с результатом вызова (unlink)? И к чему это приводит?

Извините, я не любитель Perl, поэтому я не понимаю всех этих сокращений Perl. Вот почему я задаю этот вопрос.

Спасибо!


person shybovycha    schedule 06.01.2015    source источник
comment
Я не сторонник перла Я не думаю, что авторы статьи на самом деле тоже. Это выглядит как строка кода, передаваемая от одного администратора к другому, которая по пути немного искажается.   -  person Degustaf    schedule 06.01.2015


Ответы (3)


Этот один лайнер использует много ярлыков:

  1. <*> — это частный случай оператора ромба. Вы не можете получить доступ к объекту итератора, как в других языках. Здесь он вызывает функцию glob. В контексте списка он возвращает список из всех результатов (которые являются либо строками файла, либо, как в вашем случае, содержимым каталога. Возвращаемое значение этого передается в for, который перебирает список и псевдонимы значений в $_. $_ является «переменной по умолчанию» для многих функций…
  2. Что приводит нас сюда. Многие основные функции по умолчанию имеют значение $_ без аргументов. Так что сделайте unlink и stat.
  3. (stat)[9] означает выполнение stat в контексте списка и выбор 10-го результата (индексы начинаются с нуля, это время модификации). (сравните это с доступом к массиву, например $foo[9]).
person Patrick J. S.    schedule 06.01.2015
comment
Хороший! А как насчет этого unlink результата звонка? Почему его сравнивают с stat[9]??? - person shybovycha; 06.01.2015
comment
Я не вижу причин для этого, unlink возвращает либо 1, либо значение false, в зависимости от успеха. Возможно, это очень короткий способ выполнить обе команды, но ; должен быть таким же кратким. - person Patrick J. S.; 06.01.2015
comment
Использование stat в пустом контексте также совершенно избыточно. Если бы было сравнение даты модификации, это имело бы смысл. Это просто удалит все файлы. С таким же успехом можно было бы заменить это на unlink <*> - person TLP; 06.01.2015
comment
Итератора нет. <> в контексте списка возвращает все результаты (для версий readline и glob). - person ikegami; 06.01.2015
comment
@ikegami: в некоторых частях документации ромб упоминается как итератор. Я уже говорил, что вы получаете все результаты в третьем предложении. - person Patrick J. S.; 06.01.2015
comment
@ Патрик Дж. С., конечно, есть; это итератор в скалярном контексте. Если вы вызываете итератор оператора, то ваш комментарий (вы не можете получить доступ к самому итератору) не имеет смысла, так как он обращается (использует) к оператору. В любом случае, этот комментарий неверен. - person ikegami; 06.01.2015
comment
@ Патрик Дж. С., конечно, есть; это итератор в скалярном контексте. Похоже, вы говорите, что вызываете итератор оператора, но тогда ваш комментарий (вы не можете получить доступ к самому итератору) не имеет смысла, поскольку он обращается (использует) к оператору. В любом случае, этот комментарий неверен. - person ikegami; 06.01.2015
comment
@ikegami: Я имел в виду, что нет доступного объекта итератора, как в других языках. Как вы думаете, я должен уточнить это? - person Patrick J. S.; 06.01.2015

Код

for(<*>){((stat)[9]<(unlink))}

эквивалентно:

for my $file (<*>) {
    my $mtime = (stat($file))[9];
    $mtime < unlink($file);
}

<*> также можно заменить на glob "*", что может быть более читабельно.

Код удалит все файлы в текущем каталоге. Он не будет удалять каталоги.

Обратите внимание, что последний оператор в цикле полностью избыточен. Если действует use warnings, выдается предупреждение:

Useless use of numeric lt (<) in void context

Чтобы этот код имел смысл, я бы ожидал сравнения, которое действительно имеет значение, например, сравнение $mtime с некоторым временем, чтобы узнать, какие журналы устарели, например:

if ($mtime < $oldtime) {
    unlink $file or die "Cannot unlink $file: $!";
}

Обратите также внимание на то, что при удалении файлов может быть целесообразно проверять наличие ошибок.

person TLP    schedule 06.01.2015
comment
‹*› также можно заменить на glob *, что может быть более удобочитаемым. Вы должны использовать glob в своем ответе, потому что именно ‹*› делает его похожим на дескриптор файла. - person 7stud; 06.01.2015

  1. конструкция for(‹*>) - я предполагаю, что она перебирает файлы в текущем каталоге. Но где он хранит итератор?

for-loops можно использовать для перебора массивов/списков, поэтому, если <*> создает список, то ваш код является просто циклом for. Как оказалось, <*> — это еще один способ написания glob(), который похож на регулярное выражение для получения имен файлов, а glob() возвращает список в контексте списка, то есть в контексте a для цикла обеспечивает. См.: http://perldoc.perl.org/functions/glob.html.

Обратите внимание, что одинарные кавычки не позволяют оболочке расширить *, что помешает Perl его увидеть.

person 7stud    schedule 06.01.2015
comment
Оболочка не будет интерполировать *. - person TLP; 06.01.2015
comment
@TLP, я невежда. :( - person 7stud; 06.01.2015