Как работает этот Perl One Liner, чтобы проверить, является ли каталог пустым? - PullRequest
5 голосов
/ 14 июля 2009

Сегодня я получил эту странную строку кода, она говорит мне «пусто» или «не пусто» в зависимости от того, есть ли в CWD какие-либо предметы (кроме . и ..).

Я хочу знать, как это работает, потому что для меня это не имеет смысла.

perl -le 'print+(q=not =)[2==(()=<.* *>)].empty'

Интересующий меня бит - <.* *>. Я не понимаю, как он получает имена всех файлов в каталоге.

Ответы [ 5 ]

16 голосов
/ 14 июля 2009

Это однострочный гольф. Флаг -e означает выполнение остальной части командной строки в качестве программы. -l включает автоматическую обработку конца строки.

Часть <.* *> представляет собой глобус, содержащий два шаблона для расширения: .* и *.

Эта порция

(q=not =)

- это список, содержащий единственное значение - строку «not». q=...= - это альтернативный разделитель строк, по-видимому, используемый потому, что одинарная кавычка используется для кавычек в одной строке.

Часть [...] является индексом в этом списке. Значение нижнего индекса будет равно 0 (значение «не») или 1 (ничего, что печатается как пустая строка) в зависимости от результата этого сравнения:

2 == (()=<.* *>)

Здесь много чего происходит. Сравнение проверяет, возвращал ли глобус список точно из двух элементов (предполагается, что он равен . и ..), но как это сделать - сложно. Внутренние скобки обозначают пустой список. Присвоение этому списку помещает глобус в контекст списка, чтобы он возвращал все файлы в каталоге. (В скалярном контексте он будет вести себя как итератор и возвращать только по одному за раз.) Само присвоение оценивается в скалярном контексте (находящемся в правой части сравнения) и поэтому возвращает количество назначенных элементов.

Ведущий + запрещает Perl анализировать список в качестве аргументов print. Конечный .empty объединяет строку «пусто» с тем, что вышло из списка (т. Е. Либо «нет», либо пустая строка).

7 голосов
/ 14 июля 2009
<.* *>

- это глоб, состоящий из двух шаблонов: .* - это имена файлов, начинающиеся с ., а * соответствует всем файлам (это отличается от обычных соглашений DOS / Windows).

(()=<.* *>)

оценивает глобус в контексте списка, возвращая все совпадающие имена файлов.

Затем сравнение с 2 помещает его в скалярный контекст, поэтому 2 сравнивается с количеством возвращаемых файлов. Если это число 2, то единственными записями каталога являются . и .., точка. ; -)

3 голосов
/ 14 июля 2009

<.* *> означает (glob(".*"), glob("*")). glob расширяет шаблоны файлов так же, как оболочка.

2 голосов
/ 14 июля 2009

Я считаю, что модуль B::Deparse очень помогает в расшифровке некоторых вещей, которые бросают в глаза большинству программистов, таких как конструкция q=...=:

$ perl -MO=Deparse,-p,-q,-sC 2>/dev/null << EOF
> print+(q=not =)[2==(()=<.* *>)].empty
> EOF
use File::Glob ();
print((('not ')[(2 == (() = glob('.* *')))] . 'empty'));

Конечно, это не сразу приводит к «читабельному» коду, но он наверняка преобразует некоторые камни преткновения.

0 голосов
/ 14 июля 2009

Документация для этой функции здесь . (Прокрутите ближе к концу раздела)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...