Шаг 26.
Операция <>

    На этом шаге мы рассмотрим операцию <>.

    Основное ее назначение - прочитать строку из файла, дескриптор которого является операндом этой операции. (Операнд операции <> расположен внутри угловых скобок.) Мы остановимся на специальном случае использования этой операции - операции с пустым операндом <>. В этом случае ввод осуществляется или из стандартного файла ввода, или из каждого файла, перечисленного в командной строке при запуске программы Perl. Но прежде чем перейти к описанию функционирования операции ввода с пустым операндом, остановимся на некоторых понятиях, необходимых для понимания дальнейшего.

    Для обеспечения единообразия работы программ Perl в разных операционных системах при их запуске открывается несколько стандартных файлов. Один из них предназначен для ввода данных в программу и связан со стандартным устройством ввода - клавиатурой. Этот файл и называется стандартным файлом ввода и имеет дескриптор STDIN. Для вывода информации из программы создается стандартный файл вывода, также связанный со стандартным устройством вывода операционной системы, которым является экран монитора компьютера. Этому стандартному файлу назначается дескриптор STDOUT. Для отображения разнообразных сообщений о возникающих в процессе выполнения программы ошибках создается стандартный файл ошибок, который связан со стандартным устройством вывода. Этот файл имеет дескриптор STDERR. Эти файлы не надо создавать и открывать - они уже существуют, когда наша программа начинает выполняться. Иногда их называют предопределенными файлами ввода/вывода. Таким образом, если мы, например, говорим о том, что ввод осуществляется из стандартного файла (или стандартного устройства), мы имеем в виду стандартный файл ввода с дескриптором STDIN.

    При запуске программы Perl в системе UNIX или из командной строки Windows ей можно передать параметры. Эти параметры задаются после имени файла, содержащего программу Perl, и отделяются от него и друг от друга пробелами:

    perl program.pl par1 par2 раr3

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

    Операция <> без операнда, употребленная в циклах while и for, при первом своем вычислении проверяет, пуст ли массив @ARGV. Если он пуст, то в первый элемент этого массива $ARGV[0] заносится символ "-" и операция ожидает ввода пользователя из стандартного файла ввода STDIN. Если массив @ARGV не пуст, то он содержит параметры, переданные программе при ее запуске. Операция <> трактует каждый из них как имя файла и в цикле передает в программу последовательно все строки всех файлов, указанных в командной строке. Рассмотрим простейшую программу, состоящую из одного цикла while с операцией <>, и рассмотрим ее поведение при разных способах запуска.

#! perl -w

while ($line = <>) 
{
  print $line; 
}
Текст этого примера можно взять здесь.

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

    Если при запуске передать ей имя файла, например, файла, содержащего саму же программу:

    perl  perl26_1.pl  perl26_1.pl

то программа распечатает его содержимое:

#!   perl  -w

while   ($line = <>)   
{ 
  print  $line; 
}

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

    perl  perl26_1.pl  perl26_1.pl perl26_1.pl
то программа дважды распечатает свой собственный текст.


    Замечание. В операционной системе Windows в именах файлов можно использовать пробелы. Для передачи в программу Perl файла с таким именем его следует заключать в двойные кавычки: "Name with blanks.dat".

    При выполнении операции ввода из файла встроенная переменная $_ на каждом шаге цикла хранит номер прочитанной строки файла. В случае задания нескольких имен файлов в командной строке при последовательном вводе их строк операцией <> эта переменная продолжает увеличивать свое значение при переходе на чтение строк очередного файла, т. е. она рассматривает содержимое всех файлов как один-единственный файл.

    Операцию <> и массив @ARGV можно совместно использовать для ввода в программу содержимого нескольких файлов, не связывая их с заданием имен файлов в командной строке. В любом месте программы перед первым использованием в цикле операции ввода <> можно в массив @ARGV занести имена файлов, содержимое которых необходимо обработать:

@ARGV = ("filel.dat", "file2.dat", "file3.dat"); 
for (;<>;} 
{
  # Операторы обработки строк файлов. 
}

    Этот фрагмент программы в цикле for последовательно обработает строки трех файлов file1.dat, file2.dat и file3.dat. Здесь же продемонстрирована еще одна интересная особенность операции ввода <>. Обычно прочитанная этой операцией строка присваивается скалярной переменной, как это происходило в приведенном примере, но если эта операция одна представляет выражение условия цикла, то результат ее выполнения сохраняется в специальной встроенной переменной $_. Цикл while программы приведенного примера можно записать и так:

while   (<>)    
{ 
  print;
}
Текст этого примера можно взять здесь.

    Здесь также используется то обстоятельство, что функция print без параметров по умолчанию выводит содержимое переменной $_.

    Если мы хотим передать в программу некоторые ключи, устанавливающие режим ее работы, то в начале программы следует поместить цикл, который проверяет содержимое массива @ARGV на наличие ключей в командной строке вызова программы. Один из способов подобной проверки приводится в следующем примере, где предполагается, что программе могут быть переданы ключи -d, -s и .

#! perl -w

while ($_ = $ARGV[0], /^-/) 
{
  if (/^-d/) { print $ARGV[0],"\n";}
  if (/^-s/) { print $ARGV[0],"\n";}
  if (/^-e/) { print $ARGV[0],"\n";}
  shift;
}
Текст этого примера можно взять здесь.

    При вычислении выражения условия цикла while осуществляется присваивание переменной $_ значения первого элемента массива @ARGV и проверка присутствия дефиса "-" в качестве первого символа содержимого этой переменной (операция /^-/). Операторы if проверяют содержимое переменной $_ на соответствие известным ключам и отображают их. (В реальных программах в этих операторах обычно определяют некоторые переменные, которые в дальнейшем используются для выполнения действий, присущих соответствующим ключам.) Функция shift удаляет из массива @ARGV первое значение, сдвигая оставшиеся в нем элементы на одну позицию влево: второй становится первым, третий вторым и т. д. Цикл повторяется до тех пор, пока переданные через командную строку параметры начинаются с дефиса.

    Еще одно применение операции <> связано с получением в программе имен файлов определенного каталога, удовлетворяющих заданному шаблону. Если в качестве операнда этой операции используется шаблон имен файлов, то в скалярном контексте она возвращает первое найденное имя файла в текущем каталоге, в списковом контексте - список имен файлов, удовлетворяющих заданному шаблону. (В шаблоне можно использовать метасимволы: * для произвольной цепочки символов, ? - для произвольного одиночного символа.) Если в каталоге не найдены файлы с именами, удовлетворяющими шаблону, то операция возвращает неопределенное значение. Например, выполнение следующей операции:

  $first = <*.pl>

приведет к сохранению в переменной $first имени первого файла из списка всех файлов текущего каталога с расширением pl, если таковые файлы в каталоге есть, иначе эта переменная будет иметь неопределенное значение. В списке файлы упорядочены в алфавитном порядке.

    Эта же операция в списковом контексте:

    @files = <*.pl>;

возвращает список всех файлов с расширением pl. После выполнения этой операции элементы массива @files содержат имена всех файлов с расширением pl.


    Замечание. Имена подкаталогов текущего каталога считаются файлами без расширения. Например, в возвращаемом операцией <*.*> списке файлов будут содержаться и имена подкаталогов текущего каталога.

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

    @files  = </perl/*.pl>;

сохранит в массиве @files имена всех файлов каталога /perl с расширением pl.


    Замечание. В системе Windows эта операция найдет все файлы с расширением рl в каталоге /perl текущего диска. Для задания конкретного диска следует использовать принятый в Windows синтаксис для полного имени файла: <d:/perl/*.*>. Эта операция возвратит список всех файлов каталога /perl, расположенного на диске d:.

    При использовании этой операции в выражении условия цикла while или for она последовательно на каждом шаге цикла возвращает очередное имя файла, удовлетворяющее заданному шаблону:

while   ($file = <*.pl>)    
{ 
  print   "$file\n";
}

    Употребленная в выражении условия самостоятельно, эта операция возвращает очередное имя файла в переменной $_. Например, предыдущий фрагмент можно переписать следующим образом:

while   (<*.pl>)    
{
  print  $_,   "\n"; 
}

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

    @scripts  =  glob  "*.pl";

    В скалярном контексте она возвращает имя первого файла, удовлетворяющего заданному шаблону, в списковом - список имен всех файлов. Употребленная без параметра, она использует в качестве параметра специальную переменную $_.

    На следующем шаге мы рассмотрим функцию print.




Предыдущий шаг Содержание Следующий шаг