В скриптах Perl мы должны использовать команды оболочки или вызывать функции Perl, которые имитируют операции оболочки? - PullRequest
5 голосов
/ 01 апреля 2012

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

Текстовый файл с именем some_text:

She laughed. Then both continued eating in silence, like strangers,
but after dinner they walked side by side; and there sprang up
between them the light jesting conversation of people who are free
and satisfied, to whom it does not matter where they go or what
they talk about.

Код для получения содержимого строки 5 файла

#!perl
use warnings;
use strict;

my $file = "some_text";
my $lnum = 5;
my $shellcmd = "awk 'NR==$lnum' $file";
print qx($shellcmd);
print getSrcLine($file, $lnum);

sub getSrcLine {
    my($file, $lnum) = @_;
    open FILE, $file or die "$!";
    my @ray = <FILE>;
    return $ray[$lnum-1];
}

Я спрашиваю об этом, потому что я вижу много сценариев Perl, в которых в определенный момент была вызвана команда оболочки, а в более поздний момент та же задача была выполнена путем вызова, например, функции (библиотеки или рукописной) rm -rf против File::Path::rmtree. Я просто хочу сделать это последовательным.

Что рекомендуется сделать?

Ответы [ 3 ]

14 голосов
/ 02 апреля 2012

Если для операции есть функция Perl, Perl считает, что вам следует использовать ее версию. Тем не менее, вы привели пример модуля Perl , обеспечивающего чистый способ Perl сделать это. Это сильно отличается. Там нет однозначного ответа (как в большинстве вещей), поэтому вы должны решить для себя, что делать:

  • Правильный ли подход Perl делает это правильно? Например, File :: Copy имеет некоторые ограничения, потому что он принимает некоторые неудобные решения для пользователя, поэтому многие думают, что он сломан. См., Например, File :: Copy против cp / mv .

  • Подходит ли чистый Perl-подход в приемлемое время? Иногда внешняя программа на несколько порядков быстрее. Иногда это намного медленнее.

  • Внешние команды обычно переносимы в семействе систем (например, во всех системах, подобных Linux), но, вероятно, не в семействах (например, в Windows и Linux). Ваша терпимость к этому может повлиять на ваш ответ. Даже если вы думаете, что выполняете одну и ту же команду, разные варианты Unix-подобных систем могут иметь разные переключатели для операций.

  • Передача сложных аргументов - пробелов, кавычек и специальных символов - внешним командам может заставить вас плакать. Вы должны проделать большую непростую работу, чтобы убедиться, что вы правильно обрабатываете аргументы. Подпрограммам Perl все равно.

  • Вы должны уделять гораздо больше внимания тому, что вы делаете, когда используете внешнюю команду. Если вы просто позвоните rm, Perl будет искать в вашем PATH и использовать первое, что называется rm. Это не значит, что вы думаете, что это программа. Я довольно много пишу об этом в "Техниках безопасного программирования" в Мастеринг Perl .

  • Если для подхода на основе чистого Perl требуется модуль, особенно если этот модуль имеет много сложных зависимостей, вы можете оказаться в аде зависимости или распространения в будущем.

Лично я начинаю с чистого подхода Perl, пока он не сработает для ситуации.

Для ваших конкретных примеров я бы использовал Perl. Обстреливать awk, который является прото-Perl, просто странно. Вы должны быть в состоянии сделать все, что делает awk правильно, это Perl. Если у вас есть программа awk, вы можете конвертировать ее в Perl с помощью программы a2p :

 NR==5

a2p превращает это в (по модулю некоторые установочные биты в начале):

while (<>) {
    print $_ if $. == 5;
}

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

while (<>) {
    if( $. == 5 ) {
        print;
        last;
        }
}

Не думаю, что вы должны использовать какую-то другую программу, чтобы избежать этого кода Perl.

Чтобы удалить дерево каталогов, мне нравится File :: Path . У него есть некоторые зависимости, но все они находятся в стандартной библиотеке Perl. Там очень мало боли, если таковые имеются, связанные с этим модулем. Я использовал бы это, пока я не столкнулся бы с проблемой, где это не работало.

4 голосов
/ 01 апреля 2012

Если вы хотите, чтобы ваше приложение было переносимым на не-Unix системы, то определенно закодируйте все на Perl.

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

2 голосов
/ 02 апреля 2012

Мне кажется, что работающий код должен быть первым приоритетом.Ваш произойдет сбой, если в имени файла есть пробел, например.

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

Кроме того, использование внешних инструментов может затруднить обработку ошибок.Вы даже не пытались это сделать!

С другой стороны, существует множество причин для использования внешних инструментов.Например, Perl не предоставляет такую ​​хорошую утилиту для копирования файлов, как cp;использование инструмента sort позволяет сортировать произвольные большие файлы с ограниченным объемом ОЗУ;и т.д.

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