Как я могу перевести сценарий оболочки в Perl?

Пример лямбды в Ruby следующие:

hello = lambda do
    puts('Hello')
    puts('I am inside a proc')
end

hello.call

Будет genereate следующий вывод:

Hello
I am inside a proc
15
задан brian d foy 20 July 2009 в 14:06
поделиться

5 ответов

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

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

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

Конечно, важно хорошо выбрать, что преобразовывать. Ниже я объясню, сколько шаблонов, общих для сценариев оболочки, написано на Perl, чтобы вы могли идентифицировать их внутри своего сценария и создавать замены, используя как можно больше вырезаний и вставок.

Во-первых, сценарии Perl и сценарии оболочки код + функции. То есть все, что не является объявлением функции, выполняется в том порядке, в котором оно встречается. Однако вам не нужно объявлять функции перед использованием. Это означает, что общая структура сценария может быть сохранена, хотя возможность хранить вещи в памяти (например, целый файл или его обработанную форму) позволяет упростить задачи.

Perl-сценарий в Unix, начинается примерно так:

#!/usr/bin/perl

use strict;
use warnings;

use Data::Dumper;
#other libraries

(rest of the code)

Первая строка, очевидно, указывает на команды, которые будут использоваться для запуска сценария, как это делают обычные оболочки. Следующие две строки «use» делают язык более строгим, что должно уменьшить количество ошибок, с которыми вы сталкиваетесь из-за того, что вы плохо знаете язык (или просто сделали что-то не так). Третья строка использования импортирует функцию «Дампер» модуля «Данные». Это полезно для отладки. Если вы хотите узнать значение массива или хэш-таблицы, просто выведите Dumper (что угодно).

Обратите внимание, что комментарии такие же, как и в оболочке, строки начинаются с "#".

Теперь вы вызываете внешние программы и труба к ним или труба от них. Например:

open THIS, "cat $ARGV[0] |";

Это запустит cat, передав " $ ARGV [0] ", что будет $ 1 в оболочке - первый аргумент, переданный ей. Результат этого будет передан в ваш Perl-скрипт через «ЭТО», который вы можете использовать для чтения из него, как я покажу позже.

Вы можете использовать «|» в начале или в конце строки, чтобы указать режим «конвейер к» или «конвейер от», и указать команду для запуска, а также вы можете использовать «>» или «>>» в начале, чтобы открыть файл для записи с усечением или без него, «<» для явного указания открытия файла для чтения (по умолчанию) или «+ <» и «+>» для чтения и записи. Обратите внимание, что последний сначала обрежет файл.

Другой синтаксис для "open", который позволит избежать проблем с файлами с такими символами в их именах, имеет режим открытия в качестве второго аргумента:

open THIS, "-|", "cat $ARGV[0]";

Это будет делать то же самое. Режим "- |" означает «труба от», а «| -» означает «труба до». Остальные режимы можно использовать без изменений (>, >>, <, +>, + <). Хотя есть еще что-то, что можно открыть, этого должно хватить для большинства вещей.

Но вам следует по возможности избегать вызова внешних программ. Вы можете открыть файл напрямую, выполнив open THIS, «$ ARGV [0]»; , например, и получить гораздо лучшую производительность.

Итак, какие внешние программы вы могли бы вырезать? Ну почти все. Но остановимся на основах: cat, grep, cut, head, tail, uniq, wc, sort.

CAT

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

В любом случае, основной синтаксис для cat будет:

my $filename = "whatever";
open FILE, "$filename" or die "Could not open $filename!\n";
while(<FILE>) {
  print $_;
}
close FILE;

Это открывает файл , и распечатывает все его содержимое (« while () » будет зацикливаться до EOF, присвоив каждой строке « $ _ »), и снова закроет его.

Если бы я хотел направить вывод в другой файл, я мог бы сделать это:

my $filename = "whatever";
my $anotherfile = "another";
open (FILE, "$filename") || die "Could not open $filename!\n";
open OUT, ">", "$anotherfile" or die "Could not open $anotherfile for writing!\n";
while(<FILE>) {
  print OUT $_;
}
close FILE;

Это напечатает строку в файл, обозначенный « OUT ». Вы также можете использовать STDIN , STDOUT и STDERR в соответствующих местах, не открывая их предварительно. Фактически, " print " по умолчанию равно STDOUT , а " die "по умолчанию" STDERR ".

Обратите внимание также на" or die ... "и" || die ... ". Операторы или и || означают, что следующая команда будет выполнена только в том случае, если первая вернет false (что означает пустую строку, пустую ссылку, 0 и т. д.). Команда die останавливает сценарий с сообщением об ошибке.

Основное различие между « или » и « || » - это приоритет. 1138242] или "было заменено на" || "в приведенных выше примерах, это не сработает так, как ожидалось, потому что строка будет интерпретироваться как:

open FILE, ("$filename" || die "Could not open $filename!\n");

Что совсем не то, что Ожидается. Поскольку " или " имеет более низкий приоритет, он работает. В строке, где используется « || », параметры для open передаются между скобками, что позволяет использовать « || ».

Увы, есть кое-что, что в значительной степени похоже на то, что делает cat:

while(<>) {
  print $_;
}

Это будет печатать все файлы в командной строке или все, что передано через STDIN.

GREP

Итак, как будет работать наш скрипт "grep" ? Я предполагаю "grep -E", потому что в Perl это проще, чем с помощью grep. В любом случае:

my $pattern = $ARGV[0];
shift @ARGV;
while(<>) {
        print $_ if /$pattern/o;
}

«o», переданный в $ patttern, указывает Perl на компиляцию этого шаблона только один раз, что увеличивает вашу скорость. Не в стиле «что-то, если конд». Это означает, что он выполнит "что-то", только если условие истинно. Наконец, " / $ pattern / " сам по себе то же самое, что и " Он вернет столбец , который вы запрашиваете.

Это не очень хорошая реализация, так как «split» будет сканировать всю строку. Однажды я сократил процесс с 30 минут до 2 секунд, просто не используя разделение - хотя строки были довольно большими. В любом случае, следующее имеет превосходную производительность, если ожидается, что строки будут большими, а нужные столбцы - низкими:

while(<>) {
  my ($column) = /^(?:[^,]*,){3}([^,]*),/;
  print $column, "\n";
}

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

Если вам нужны позиционные столбцы , вы можете использовать:

while(<>) {
  print substr($_, 5, 10), "\n";
}

Что выведет 10 символов, начиная с шестого (опять же, 0 означает первый символ).

HEAD

Это довольно просто:

my $printlines = abs(shift);
my $lines = 0;
my $current;
while(<>) {
  if($ARGV ne $current) {
    $lines = 0;
    $current = $ARGV;
  }
  print "$_" if $lines < $printlines;
  $lines++;
}

Здесь следует обратить внимание. Я использую «ne» для сравнения строк. Теперь $ ARGV всегда будет указывать на текущий читаемый файл, поэтому я отслеживаю их, чтобы возобновить подсчет после чтения нового файла. Также обратите внимание на более традиционный синтаксис для «if», а также на пост-фиксированный.

Я также использую упрощенный синтаксис, чтобы получить количество печатаемых строк. Когда вы используете «shift» отдельно, он будет принимать «shift @ARGV». Также обратите внимание, что shift, помимо изменения @ARGV, вернет элемент, который был перемещен из него.

Как и в случае с оболочкой, нет различия между числом и строкой - вы просто используете его. Даже такие вещи, как "2" + "2", будут работать. На самом деле Perl еще более снисходительно относится ко всему, кроме чисел, как к 0, так что вы можете быть осторожны с ним.

Этот сценарий очень неэффективен, поскольку он читает ВСЕ файл, а не только необходимые строки . Давайте улучшим это, и увидите пару важных ключевых слов в процессе:

my $printlines = abs(shift);
my @files;
if(scalar(@ARGV) == 0) {
  @files = ("-");
} else {
  @files = @ARGV;
}
for my $file (@files) {
  next unless -f $file && -r $file;
  open FILE, "<", $file or next;
  my $lines = 0;

  while(<FILE>) {
    last if $lines == $printlines;
    print "$_";
    $lines++;
  }

  close FILE;
}

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

Затем «последний» используется для немедленного выхода из цикла. Мы используем его, чтобы остановить чтение файла, когда мы достигли необходимого количества строк. Это правда, что мы читаем на одну строку слишком много, но наличие «last» в этой позиции ясно показывает, что строки после нее не будут выполнены.

Также есть «redo», который вернется в начало цикла. , но без переоценки условия и без получения следующего элемента.

TAIL

Здесь я проделаю небольшой трюк.

my $skiplines = abs(shift);
my @lines;
my $current = "";
while(<>) {
  if($ARGV ne $current) {
    print @lines;
    undef @lines;
    $current = $ARGV;
  }
  push @lines, $_;
  shift @lines if $#lines == $skiplines;
}
print @lines;

Хорошо, я комбинирую "push", который добавляет значение в массив, с "shift", который берет что-то с начала массив. Если вам нужен стек, вы можете использовать push / pop или shift / unshift. Смешайте их, и у вас будет очередь. Я держу свою очередь не более чем с 10 элементами с $ # lines , которые дадут мне индекс последнего элемента в массиве. Вы также можете получить количество элементов в @lines с помощью скаляра (@lines) .

UNIQ

Теперь uniq удаляет только повторяющиеся последовательные строки, что должно быть легко с тем, что вы видели до сих пор. Поэтому я устраню их все:

my $current = "";
my %lines;
while(<>) {
  if($ARGV ne $current) {
    undef %lines;
    $current = $ARGV;
  }
  print $_ unless defined($lines{$_});
  $lines{$_} = "";
}

Теперь я храню весь файл в памяти внутри % строк . Использование сигилла % указывает на то, что это хеш-таблица. Я использую строки в качестве ключей и ничего не сохраняю в качестве значений, так как значения меня не интересуют. Я проверяю, где существует ключ, с помощью "defined ($ lines {$ _})", который проверяет, определено ли значение, связанное с этим ключом, или нет; ключевое слово "if" работает так же, как "if", но с противоположным эффектом, поэтому оно печатает строку только в том случае, если строка НЕ ​​определена.

Также обратите внимание на синтаксис $ lines {$ _} = "" как способ сохранить что-то в хеш-таблице. Обратите внимание на использование {} для хеш-таблицы, в отличие от [] для массивов.

WC

На самом деле это будет использовать много вещей, которые мы видели:

my $current;
my %lines;
my %words;
my %chars;
while(<>) {
  $lines{"$ARGV"}++;
  $chars{"$ARGV"} += length($_);
  $words{"$ARGV"} += scalar(grep {$_ ne ""} split /\s/);
}

for my $file (keys %lines) {
  print "$lines{$file} $words{$file} $chars{$file} $file\n";
}

Три новых вещи . Два - это оператор «+ =», который должен быть очевиден, и выражение «for». По сути, «for» будет назначать каждый элемент массива указанной переменной. «My» используется для объявления переменной, хотя он не нужен, если был объявлен ранее. Внутри этих скобок могла бы быть переменная @array. Выражение "keys% lines" вернет как массив, который они ключи (имена файлов), которые существуют для хэш-таблицы "% lines". Остальное должно быть очевидно.

Третья вещь, которую я фактически добавил только для уточнения ответа, - это «grep». Формат здесь:

grep { code } array

Он запускает «код» для каждого элемента массива, передавая элемент как «$ _». Затем grep вернет все элементы, для которых код оценивается как «истина» (не 0, не «» и т. Д.). Это позволяет избежать подсчета пустых строк, являющихся результатом последовательных пробелов.

Аналогично " Вы можете проверить определенные условия для файлов следующим образом:

for my $file (@ARGV) {
  print "$file is a file\n" if -f "$file";
  print "$file is a directory\n" if -d "$file";
  print "I can read $file\n" if -r "$file";
  print "I can write to $file\n" if -w "$file";
}

Я не пытаюсь быть здесь исчерпывающим, существует множество других подобных тестов. Я также могу создавать шаблоны "glob", такие как "*" и "?" Оболочки, например:

for my $file (glob("*")) {
  print $file;
  print "*" if -x "$file" && ! -d "$file";
  print "/" if -d "$file";
  print "\t";
}

Если вы объедините это с "chdir", вы также можете эмулировать "find":

sub list_dir($$) {
  my ($dir, $prefix) = @_;
  my $newprefix = $prefix;
  if ($prefix eq "") {
    $newprefix = $dir;
  } else {
    $newprefix .= "/$dir";
  }
  chdir $dir;
  for my $file (glob("*")) {
    print "$prefix/" if $prefix ne "";
    print "$dir/$file\n";
    list_dir($file, $newprefix) if -d "$file";
  }
  chdir "..";
}

list_dir(".", "");

Здесь мы видим, наконец, функция. Функция объявляется с синтаксисом:

sub name (params) { code }

Строго говоря, "(params)" не является обязательным. Заявленный параметр, который я использовал, « ($$) » означает, что я получаю два скалярных параметра. Я мог бы также иметь там « @ » или «% ». В массиве « @_ » переданы все параметры. Строка « my ($ dir, $ prefix) = @_ » - это просто простой способ присвоить первые два элемента этого массива переменным $ dir и $ prefix .

Эта функция ничего не возвращает (на самом деле это процедура ), но у вас могут быть функции, которые возвращают значения, просто добавляя к нему « return something; », а он возвращает «something».

Остальное должно быть довольно очевидно.

СМЕШИВАНИЕ ВСЕГО

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

В этом первом примере у меня есть два файла, файл names.txt, имена и номера телефонов, system.txt, с системами и именем ответственного за них. Вот они:

names.txt

John Doe, (555) 1234-4321
Jane Doe, (555) 5555-5555
The Boss, (666) 5555-5555

systems.txt

Sales, Jane Doe
Inventory, John Doe
Payment, That Guy

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

#!/usr/bin/perl

use strict;
use warnings;

open FILE, "names.txt";

while(<FILE>) {
  my ($name) = /^([^,]*),/;
  my $system = get_system($name);
  print $_ . ", $system\n";
}

close FILE;

sub get_system($) {
  my ($name) = @_;
  my $system = "";

  open FILE, "systems.txt";

  while(<FILE>) {
    next unless /$name/o;
    ($system) = /([^,]*)/;
  }

  close FILE;

  return $system;
}

Но этот код работать не будет. Perl будет жаловаться, что эта функция была использована слишком рано для проверки прототипа, но это всего лишь предупреждение. Он выдаст ошибку в строке 8 (первый цикл while), жалуясь на строку чтения на закрытом дескрипторе файла. Здесь произошло то, что « ФАЙЛ » является глобальным, поэтому функция get_system меняет его. Давайте перепишем его, исправив обе вещи:

#!/usr/bin/perl

use strict;
use warnings;

sub get_system($) {
  my ($name) = @_;
  my $system = "";

  open my $filehandle, "systems.txt";

  while(<$filehandle>) {
    next unless /$name/o;
    ($system) = /([^,]*)/;
  }

  close $filehandle;

  return $system;
}

open FILE, "names.txt";

while(<FILE>) {
  my ($name) = /^([^,]*),/;
  my $system = get_system($name);
  print $_ . ", $system\n";
}

close FILE;

Это не даст никаких ошибок или предупреждений и не будет работать. Он возвращает только системы, но не имена и номера телефонов! Что случилось? Что ж, произошло то, что мы делаем ссылку на " $ _ " после вызова get_system , но при чтении файла get_system перезаписывает значение $ _ !

Чтобы этого избежать, мы сделаем $ _ локально внутри get_system . Это даст ему локальную область видимости, и исходное значение будет восстановлено после возврата из get_system :

#!/usr/bin/perl

use strict;
use warnings;

sub get_system($) {
  my ($name) = @_;
  my $system = "";
  local $_;

  open my $filehandle, "systems.txt";

  while(<$filehandle>) {
    next unless /$name/o;
    ($system) = /([^,]*)/;
  }

  close $filehandle;

  return $system;
}

open FILE, "names.txt";

while(<FILE>) {
  my ($name) = /^([^,]*),/;
  my $system = get_system($name);
  print $_ . ", $system\n";
}

close FILE;

И это по-прежнему не работает! Он печатает новую строку между именем и системой. Что ж, Perl читает строку, включая любые символы новой строки, которые в ней могут быть. Есть изящная команда, которая удаляет новые строки из строк, « chomp », которую мы будем использовать для решения этой проблемы. А поскольку не у каждого имени есть система, мы могли бы также избежать печати запятой, когда это произойдет:

#!/usr/bin/perl

use strict;
use warnings;

sub get_system($) {
  my ($name) = @_;
  my $system = "";
  local $_;

  open my $filehandle, "systems.txt";

  while(<$filehandle>) {
    next unless /$name/o;
    ($system) = /([^,]*)/;
  }

  close $filehandle;

  return $system;
}

open FILE, "names.txt";

while(<FILE>) {
  my ($name) = /^([^,]*),/;
  my $system = get_system($name);
  chomp;
  print $_;
  print ", $system" if $system ne "";
  print "\n";
}

close FILE;

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

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

#!/usr/bin/perl

use strict;
use warnings;

our %systems;
open SYSTEMS, "systems.txt";
while(<SYSTEMS>) {
  my ($system, $name) = /([^,]*),(.*)/;
  $systems{$name} = $system;
}
close SYSTEMS;

open NAMES, "names.txt";
while(<NAMES>) {
  my ($name) = /^([^,]*),/;
  chomp;
  print $_;
  print ", $systems{$name}" if defined $systems{$name};
  print "\n";
}
close NAMES;

К сожалению, это не работает. Никакой системы не появляется! Что случилось? Что ж, давайте посмотрим, что содержится в «% systems », используя Data :: Dumper :

#!/usr/bin/perl

use strict;
use warnings;

use Data::Dumper;

our %systems;
open SYSTEMS, "systems.txt";
while(<SYSTEMS>) {
  my ($system, $name) = /([^,]*),(.*)/;
  $systems{$name} = $system;
}
close SYSTEMS;

print Dumper(%systems);

open NAMES, "names.txt";
while(<NAMES>) {
  my ($name) = /^([^,]*),/;
  chomp;
  print $_;
  print ", $systems{$name}" if defined $systems{$name};
  print "\n";
}
close NAMES;

Результат будет примерно таким:

$VAR1 = ' Jane Doe';
$VAR2 = 'Sales';
$VAR3 = ' That Guy';
$VAR4 = 'Payment';
$VAR5 = ' John Doe';
$VAR6 = 'Inventory';
John Doe, (555) 1234-4321
Jane Doe, (555) 5555-5555
The Boss, (666) 5555-5555

Те $ VAR1 / $ VAR2 / etc - это то, как Dumper отображает хеш-таблицу. Нечетные числа - ключи, а следующие за ним четные числа являются значениями. Теперь мы можем видеть, что каждое имя в % systems имеет предшествующий пробел! Глупая ошибка с регулярным выражением, давайте исправим ее:

#!/usr/bin/perl

use strict;
use warnings;

our %systems;
open SYSTEMS, "systems.txt";
while(<SYSTEMS>) {
  my ($system, $name) = /^\s*([^,]*?)\s*,\s*(.*?)\s*$/;
  $systems{$name} = $system;
}
close SYSTEMS;

open NAMES, "names.txt";
while(<NAMES>) {
  my ($name) = /^\s*([^,]*?)\s*,/;
  chomp;
  print $_;
  print ", $systems{$name}" if defined $systems{$name};
  print "\n";
}
close NAMES;

Итак, здесь мы агрессивно удаляем любые пробелы в начале или конце имени и системы. Есть и другие способы сформировать это регулярное выражение, но это не относится к делу. Есть еще одна проблема с этим скриптом, которую вы увидите, если в ваших файлах "names.txt" и / или "systems.txt" в конце будет пустая строка. Предупреждения выглядят следующим образом:

Use of uninitialized value in hash element at ./exemplo3e.pl line 10, <SYSTEMS> line 4.
Use of uninitialized value in hash element at ./exemplo3e.pl line 10, <SYSTEMS> line 4.
John Doe, (555) 1234-4321, Inventory
Jane Doe, (555) 5555-5555, Sales
The Boss, (666) 5555-5555
Use of uninitialized value in hash element at ./exemplo3e.pl line 19, <NAMES> line 4.

Здесь произошло то, что ничего не попало в переменную " $ name " при обработке пустой строки. Есть много способов обойти это, но я выбрал следующий:

#!/usr/bin/perl

use strict;
use warnings;

our %systems;
open SYSTEMS, "systems.txt" or die "Could not open systems.txt!";
while(<SYSTEMS>) {
  my ($system, $name) = /^\s*([^,]+?)\s*,\s*(.+?)\s*$/;
  $systems{$name} = $system if defined $name;
}
close SYSTEMS;

open NAMES, "names.txt" or die "Could not open names.txt!";
while(<NAMES>) {
  my ($name) = /^\s*([^,]+?)\s*,/;
  chomp;
  print $_;
  print ", $systems{$name}" if defined($name) && defined($systems{$name});
  print "\n";
}
close NAMES;

Регулярные выражения теперь требуют хотя бы одного символа для имени и системы, и мы проверяем, есть ли " вы можете перевести их на Perl с помощью A2P и S2P .

  • Perl может быть написан объектно-ориентированным способом.

  • Существует несколько версий Perl. На момент написания этой статьи стабильной является версия 5.8.8 и доступна версия 5.10.0. В разработке также находится Perl 6, но опыт научил всех не ждать его слишком долго.

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

    Надеюсь, это помогло.

    ОТКАЗ ОТ ОТВЕТСТВЕННОСТИ

    Я НЕ пытаюсь преподавать Perl, и вам понадобится хотя бы немного справочный материал. Существуют рекомендации по использованию хороших навыков Perl, например, использование " use strict; " и "

    76
    ответ дан 30 November 2019 в 23:51
    поделиться

    Я не знаю, что находится в вашем сценарии оболочки, но не забывайте, что есть такие инструменты, как

    1. a2p - awk-to-perl
    2. s2p - sed-to-perl

    и, возможно, больше. Стоит взглянуть вокруг.

    Вы можете обнаружить, что из-за мощности / возможностей Perl это не такая уж большая работа, поскольку вы, возможно, прыгали через обручи с различными функциями и служебными программами bash, чтобы сделать что-то, что выходит из Perl изначально.

    Как и в любом проекте миграции, полезно иметь несколько стандартных регрессионных тестов для запуска с обоими решениями, поэтому, если у вас их нет, я бы сначала сгенерировал их.

    5
    ответ дан 30 November 2019 в 23:51
    поделиться

    Я удивлен, что никто еще не упомянул модуль Shell , который включен в ядро ​​Perl, что позволяет выполнять внешние команды с использованием синтаксиса вызова функций. Например (адаптировано из синопсиса):

    use Shell qw(cat ps cp);
    $passwd = cat '</etc/passwd';
    @pslines = ps '-ww';
    cp "/etc/passwd", "/tmp/passwd";
    

    При условии, что вы используете скобки, вы можете даже вызывать другие программы в $ PATH , которые вы не упомянули в строке use , например:

    gcc('-o', 'foo', 'foo.c');
    

    Обратите внимание, что Shell собирает STDOUT подпроцесса и возвращает его как строку или массив. Это упрощает создание сценариев, но это не самый эффективный способ, и могут возникнуть проблемы, если вы полагаетесь на небуферизованный вывод команды.

    В документации модуля упоминаются некоторые недостатки, такие как внутренние команды оболочки (например, cd ) нельзя вызывать с использованием того же синтаксиса. Фактически они рекомендуют не использовать модуль для производственных систем! Но это, безусловно, может быть полезным костылем, на который можно опереться, пока вы не перенесете свой код на «правильный» Perl.

    5
    ответ дан 30 November 2019 в 23:51
    поделиться

    Ну…

    Вы можете начать ваш "Perl" скрипт с:

    #!/bin/bash
    

    Затем, если bash был установлен в этом месте, perl автоматически вызовет интерпретатор bash для его запуска.

    Изменить: Или, может быть, ОС будет перехватить вызов и не дать ему попасть в Perl. Мне трудно найти документацию о том, как это работает. Комментарии к документации приветствуются.

    -15
    ответ дан 30 November 2019 в 23:51
    поделиться

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

    Не существует транслятора оболочки на Perl. Была давняя шутка о переводчике csh-to-Perl, которому вы могли бы отправить свой сценарий по электронной почте, но на самом деле это был просто Том Кристейнсен, который переводил его для вас, чтобы показать вам, насколько крутым был Perl в начале 90-х. Рэндал Шварц загрузил переводчик sh-to-Perl, но вы должны проверить дату загрузки: это был день дурака. Его сценарий просто обернул все в систему .

    Что бы вы ни делали, не теряйте исходный сценарий оболочки. :)

    4
    ответ дан 30 November 2019 в 23:51
    поделиться
    Другие вопросы по тегам:

    Похожие вопросы: