Операция ввода команды
Ни одна программа не может функционировать
сама по себе, не получая и не посылая информацию во внешнюю среду. Perl предоставляет
несколько способов получения программой данных извне и вывода информации из
выполняющегося сценария. В процессе функционирования программы может потребоваться
выполнить некоторую команду операционной системы и проанализировать результаты
ее выполнения, прочитать данные из внешнего файла или группы файлов, записать
результаты вычислений во внешний файл или отобразить их на экране монитора —
все эти действия реализуются разнообразными операциями и функциями языка Perl.
Простейшее взаимодействие с операционной
системой, в которой выполняется программа Perl, реализуется операцией заключения
строки данных в обратные кавычки. Содержимое такой строки передается на выполнение
операционной системы, которая возвращает результат выполнения команды в эту
же строку.
Для чтения из файла используется
операция "ромб" о, которой в качестве операнда передается дескриптор
файла. В этой главе мы не будем обсуждать ввод из файла через его дескриптор,
отнеся рассмотрение этого вопроса в следующую главу, полностью посвященную работе
с файлами. Здесь мы расскажем о том, как работает операция "ромб"
в случае отсутствия операнда, представляющего дескриптор файла. В этом случае эта операция может читать записи из стандартного файла ввода STDIN или получать информацию, передаваемую программе через командную строку.
Для отображения в стандартный файл
вывода STDOUT используется уже знакомая нам функция print, которая, однако,
может выводить информацию и в файл, определенный своим дескриптором.
Заключенная в обратные кавычки
"•"• строка символов является всего лишь удобной формой записи операции
ввода команды операционной системы qx{}, с которой мы уже знакомы (см. часть
4).
Когда интерпретатор Perl встречает строковый литерал в обратных кавычках, он
осуществляет подстановку в нее значений скалярных переменных и переменных массивов
и передает получившуюся строку, как команду, на выполнение операционной системе.
Последняя выполняет ее и возвращает в строковый литерал результаты вывода команды
на стандартное устройство вывода, которым обычно является экран монитора. В
связи с таким "поведением" строкового литерала в обратных кавычках
его иногда называют псевдолитералом.
Операция ввода команды различает скалярный и списковый контексты, в которых
она может выполняться. В скалярном контексте возвращается одна строка, содержащая
весь вывод на экран монитора выполненной команды, включая символы новой строки
в случае многострочного вывода. В списковом контексте возвращается список значений,
каждое из которых содержит одну строку вывода. Пример 6.1 демонстрирует использование
операции ввода команды в соответствующих контекстах.
#! peri -w
$command = "dir";
$scalar = ~$command'; # Скалярный контекст. ,
@list = '$command~; # Списковый контекст.
print $scalar;
print $list[0], $list[lj;
При выполнении операции заключения в кавычки сначала осуществляется подстановка
значения скалярной переменной $ command, а потом полученная строка передается
на выполнение операционной системы. Переменная $scaiar (скалярный контекст)
содержит весь вывод на экран монитора содержимого текущего каталога, поэтому
при ее печати мы увидим все, что вывела команда dir. Когда результаты выполнения
команды присваиваются массиву @iist (списковый контекст), то каждая строка вывода
команды становится элементом массива, поэтому последний оператор печати примера
6.1 выводит первую и вторую строки.
В списковом контексте разбиение вывода команды операционной системы на элементы
списка осуществляется в соответствии со значением встроенной переменной $/,
которое используется в качестве разделителя. По умолчанию эта переменная содержит
символ конца строки "\п" — поэтому и разбиение на элементы
происходит по строкам. Присваивая этой переменной новое значение, мы тем самым
определяем новое значение разделителя, которое будет использоваться при формировании
элементов списка. Разделителем может быть любая последовательность символов.
Например, в примере 6.2 в качестве разделителя задается строка "<КАТАЛОГ>".
§! peri -w
$/ = "<КАТАЛОГ>";
@list = ~dir s ; t Списковый контекст.
print $list[l], $list[2];
Теперь, в отличие от примера 6.1, элемент массива $iist[0j содержит не первую
строку вывода команды dir, а вывод команды до первой встретившейся в нем последовательности
символов "<КАТАЛОГ>". Аналогично, элемент $list[l] содержит
вывод команды до следующей встретившейся последовательности СИМВОЛОВ "<КАТАЛОГ>"
И Т. Д.
Команда, содержащаяся в псевдолитерале, выполняется всякий раз, как вычисляется
этот псевдолитерал. Встроенная переменная $? содержит числовое значение состояния
выполненной команды.
(Об интерпретации значений встроенной переменной $ ? см. часть 14 щелкни
здесь.)
Хотим обратить внимание читателя
еще раз на тот факт, что операция ввода команды возвращает вывод на стандартное
устройство вывода операционной системы. При выполнении команды можно направить
ее вывод на другое устройство, например, в файл. Для этого в строке после имени
команды и всех необходимых для ее выполнения параметров следует задать символ
">", после которого ввести имя файла. В этом случае на экран монитора
ничего выводиться не будет, а следовательно и ничего не будет возвращаться в
псевдолитерал, т. е. после выполнения такой команды псевдолитерал будет содержать
неопределенное значение (пример 6.3).
#! peri -w - $/ = "<КАТАЛОГ>";
$list = 'dir >file.dat~; # Вывод осуществляется в файл file.dat print $list;
# Оператор ничего не напечатает!
Замечание
Обобщенная форма операции заключения в обратные кавычки
qx {} работает точно так же, как и операция заключения в обратные кавычки "
* '".
Операция ()
Для нашего читателя эта операция
не является совсем уж новой. Несколько слов о ней было сказано в части 4;
в некоторых примерах мы ее использовали для ввода пользователем данных
в программу Perl. Основное ее назначение — прочитать строку из файла, дескриптор
которого является операндом этой операции. (Операнд операции о расположен внутри
угловых скобок.) Мы не будем сейчас объяснять, что такое дескриптор файла, зачем
он нужен и какую функцию выполняет в программах Perl. Эти вопросы будут нами
подробно рассмотрены в следующей главе, посвященной работе с файлами. Здесь
же мы остановимся на специальном случае использования этой операции — операции
с пустым операндом 0. В этом случае ввод осуществляется или из стандартного
файла ввода, или из каждого файла, перечисленного в командной строке при запуске
программы Perl. Но прежде чем перейти к описанию функционирования операции ввода
с пустым операндом, остановимся на некоторых понятиях, необходимых для понимания
дальнейшего.
Для обеспечения единообразия работы программ Perl в разных операционных системах
при их запуске открывается несколько стандартных файлов. Один из них предназначен
для ввода данных в программу и связан со стандартным устройством ввода — клавиатурой.
Этот файл и называется стандартным файлом ввода и имеет дескриптор STDIN. Для
вывода информации из программы создается стандартный файл вывода, также связанный
со стандартным устройством вывода операционной системы, которым является экран
монитора компьютера. Этому стандартному файлу назначается дескриптор STDOUT.
Для отображения разнообразных сообщений о возникающих в процессе выполнения
программы ошибках создается стандартный файл ошибок, который связан со стандартным
устройством вывода. Этот файл имеет дескриптор STDERR. Эти файлы не надо создавать
и открывать — они уже существуют, когда наша программа начинает выполняться.
Иногда их называют предопределенными файлами ввода/вывода. Таким образом, если
мы, например, говорим о том, что ввод осуществляется из стандартного файла (или
стандартного устройства), мы имеем в виду стандартный файл ввода с дескриптором
STDIN.
При запуске программы Perl в системе UNIX или из командной строки Windows ей
можно передать параметры. Эти параметры задаются после имени файла, содержащего
программу Perl, и отделяются от него и друг от друга пробелами:
peri program.pl parl par2 рагЗ
Параметрами могут быть ключи (обычно символ с лидирующим дефисом, например,
-v), которые устанавливают определенные режимы работы программы, или имена файлов,
содержимое которых должна обработать программа. Все передаваемые в программу
параметры сохраняются в специальном встроенном массиве @ARGV. Если не передается
ни одного параметра, то этот массив пуст.
Операция о без операнда, употребленная в циклах while и for, при первом своем
вычислении проверяет, пуст ли массив @ARGV. Если он пуст, то в первый элемент
этого массива $ARGV[O] заносится символ "-" и операция ожидает ввода
пользователя из стандартного файла ввода STDIN. Если массив @ARGV не пуст, то
он содержит параметры, переданные программе при ее запуске. Операция о трактует
каждый из них как имя файла и в цикле передает в программу последовательно все
строки всех файлов, указанных в командной строке. Рассмотрим простейшую программу
(пример 6.4), состоящую из одного цикла while с операцией <>, и рассмотрим
ее поведение при разных способах запуска.
i! peri -w
while ($line = <>) {
print $line; }
При ее запуске без параметров она будет ожидать ввода пользователя с клавиатуры
и в цикле распечатывать вводимые им строки, пока пользователь не завершит ввод
комбинацией клавиш <Ctrl>+<Z>, интерпретируемой как конец файла.
Если при запуске передать ей имя файла, например, файла, содержащего саму же
программу,
peri examp6_4.pi examp6_4.pi
то программа примера 6.4 распечатает его содержимое:
f! peri -w
while ($line = <>) {
print $line; }
Замечание
Предполагается, что программа примера
6.4 сохранена в файле с именем examp6_4.pl.
Если эту же программу запустить,
задав в командной строке дважды имя файла программы,
peri examp6_4.pl examp6_4.pl examp6_4.pl
то программа дважды распечатает свой собственный текст.
Замечание
В операционной системе Windows в именах
файлов можно использовать пробелы. Для передачи в программу Perl файла с таким
именем его следует заключать в двойные кавычки: "Name with blanks.dat".
При выполнении операции ввода
из файла встроенная переменная $. на каждом шаге цикла хранит номер прочитанной
строки файла. В случае задания нескольких имен файлов в командной строке при
последовательном вводе их строк операцией о эта переменная продолжает увеличивать
свое значение при переходе на чтение строк очередного файла, т. е. она рассматривает
содержимое всех файлов как один-единственный файл.
Операцию о и массив @ARGV можно совместно использовать для ввода в программу
содержимого нескольких файлов, не связывая их с заданием имен файлов в командной
строке. В любом месте программы перед первым использованием в цикле операции
ввода <> можно в массив SARGV занести имена файлов, содержимое которых
необходимо обработать:
@ARGV = ("filel.dat", "file2.dat", "file3.dat");
for (;<>;) {
Операторы обработки строк файлов }
Этот фрагмент программы в цикле for последовательно обработает строки трех файлов
filel.dat, file2.dat и file3.dat. Здесь же продемонстрирована еще одна интересная
особенность операции ввода о. Обычно прочитанная этой операцией строка присваивается
скалярной переменной, как это происходило в примере 6.4, но если эта операция
одна представляет выражение условия цикла, то результат ее выполнения сохраняется
в специальной встроенной переменной $_. Цикл while программы примера 6.4 можно
записать и так:
while (<>) ( print;
}
Здесь также используется то обстоятельство, что функция print без параметров
по умолчанию выводит содержимое переменной $_.
Если мы хотим передать в программу некоторые ключи, устанавливающие режим ее
работы, то в начале программы следует поместить цикл, который проверяет содержимое
массива @ARGV на наличие ключей в командной строке вызова программы. Один из
способов подобной проверки приводится в примере 6.5, где предполагается, что
программе могут быть переданы ключи
-d, -s и -е.
f! peri -w
while ($_ = $ARGV[0], / ^ -/) {
if(/ ^ -d/) { print $ARGV[0],"\n";}
if(/ ^ -s/) { print $ARGV[0]-, "\n"; }
1£(/ ^ -е/) { print $ARGV[0],"\n"; }
shift; }
При вычислении выражения условия цикла while осуществляется присваивание переменной
$_ значения первого элемента массива @ARGV и проверка присутствия дефиса "-"
в качестве первого символа содержимого этой переменной (операция / Л
-/). Операторы if проверяют содержимое переменной $_ на соответствие известным
ключам и отображают их. (В реальных программах в этих операторах обычно определяют
некоторые переменные, которые в дальнейшем используются для выполнения действий,
присущих соответствующим ключам.) Функция shift удаляет из массива @ARGV первое
значение, сдвигая оставшиеся в нем элементы на одну позицию влево: второй становится
первым, третий вторым и т. д. Цикл повторяется до тех пор, пока переданные через
командную строку параметры начинаются с дефиса. Еще одно применение операции
<> связано с получением в программе имен файлов определенного каталога,
удовлетворяющих заданному шаблону. Если в качестве операнда этой операции используется
шаблон имен файлов, то в скалярном контексте она возвращает первое найденное
имя файла в текущем каталоге, в списковом контексте — список имен файлов, удовлетворяющих
заданному шаблону. (В шаблоне можно использовать метасимволы: * для произвольной
цепочки символов, ? для произвольного одиночного символа.) Если в каталоге не
найдены файлы с именами, удовлетворяющими шаблону, то операция возвращает неопределенное
значение. Например, выполнение следующей операции
$first = <*.pl>;
приведет к сохранению в переменной $ first имени первого файла из списка всех
файлов текущего каталога с расширением pi, если таковые файлы в каталоге есть,
иначе эта переменная будет иметь неопределенное значение. В списке файлы упорядочены
в алфавитном порядке. Эта же операция в списковом контексте
gfiles = <*.pl>;
возвращает список всех файлов с расширением pi. После выполнения этой операции
элементы массива @files содержат имена всех файлов с расширением pi.
Замечание
Имена подкаталогов текущего каталога
считаются файлами без расширения. Например, в возвращаемом операцией <*.
*> списке файлов будут содержаться и имена подкаталогов текущего каталога.
Если при задании шаблона файла
явно указать каталог, то эта операция возвратит список файлов из указанного
каталога, имена которых удовлетворяют заданному шаблону. Например, операция
@files = </perl/*.pl>;
сохранит в массиве @flies имена всех файлов каталога /peri с расширением pi.
Замечание
В системе Windows эта операция найдет
все файлы с расширением р! в каталоге /peri текущего диска. Для задания конкретного
диска следует использовать принятый в Windows синтаксис для полного имени файла:
<d: /peri/*. *>. Эта операция возвратит список всех файлов каталога /peri,
расположенного на диске d:.
При использовании этой операции
в выражении условия цикла while или for она последовательно на каждом шаге цикла
возвращает очередное имя файла, удовлетворяющее заданному шаблону:
while ($file = <*.pl>) (
print "$file\n"; }
Употребленная в выражении условия самостоятельно, эта операция возвращает очередное
имя файла в переменной $_. Например, предыдущий фрагмент можно переписать следующим
образом:
while (<*.pl>) {
print $_, "\п"; }
Операция получения имен файлов, соответствующих заданному шаблону, реализуется
с помощью внутренней функции glob, единственным параметром которой является
шаблон имен файлов. Эту функцию можно использовать самостоятельно для получения
соответствующих имен файлов:
• @scripts = glob "*.pl";
В скалярном контексте она возвращает имя первого файла, удовлетворяющего заданному
шаблону, в списковом — список имен всех файлов. Употребленная без параметра,
она использует в качестве параметра специальную переменную $_.