Новые книги

Хакер — это человек, который чем-то увлечен, будь то компьютеры, написание книг, природа или спорт. Это человек, который, благодаря этой своей увлеченности, испытывает любопытство ко всему, связанному с его увлечением. Если хакер любит компьютеры, то будет стараться узнать как можно больше о компьютерах, а также о том, как ими пользуются другие люди. Хакеры уважают предмет своего увлечения. Для компьютерного хакера это означает уважение к компьютерам, которые предоставляют людям возможность входить в контакт друг с другом и получать информацию со всего мира, а это в свою очередь означает, что он уважает других людей и не допустит умышленного использования своих знаний о компьютерах в целях развлекательных или разрушительных. Серьезный компьютерный взломщик просто хочет знать обо всем, что делается в мире, особенно в мире компьютеров. Настоящий Компьютерный Взломщик — это компьютерный энтузиаст, и, что более важно, вселенский энтузиаст. Я надеюсь, что вы будете энтузиастами.
В книге описывается сервер сценариев Windows Script Host (WSH) версии 5.6, который является одним из стандартных компонентов Windows ХР, а также может быть установлен в более ранних версиях Windows. Приводятся сценарии на языках VBScript и JScript, иллюстрирующие применение стандартных объектов WSH 5.6, включая создание из сценариев дочерних процессов и запуск сценариев на удаленных компьютерах. В качестве более сложных примеров рассматриваются сценарии, работающие с базами данных, управляющие приложениями Microsoft Office, организующие графический пользовательский интерфейс, использующие технологии ADSI (Active Directory Service Interface) и WMI (Windows Management Instrumentation) для решения задач администрирования. Освещены вопросы практической работы с XML-файлами и создания СОМ-объектов. Особое внимание уделяется вопросам безопасности при работе со сценариями, приводятся конкретные примеры настроек политик безопасности. К книге прилагается дискета с исходными текстами большинства примеров.

ГЛАВА 2. Доступ к файлам


2.1.4. paths - нахождение пути доступа к исполняемым файлам, со специальными опциями


    ИМЯ:  paths

paths Определитель маршрутных имен файлов со специальными опциями

НАЗНАЧЕНИЕ

Выводит на экран каталог, в котором располагается файл, выдает имя файла в длинном формате или ищет файлы с установленным битом пользовательского идентификатора (setuid bit files) в каталогах по указанному маршруту.

ФОРМАТ ВЫЗОВА
    paths [-l] [-s] file [file ...]
ПРИМЕР ВЫЗОВА
    $ paths -l ed ex vi

Выдает в длинном формате имена файлов, которые являются исполняемыми модулями редакторов ed, ex и vi

ТЕКСТ ПРОГРАММЫ
   1   :
   2   # @(#) paths v1.0 Path locator with special options Author: Russ Sage
   2а    Определитель местонахождения файлов со специальными опциями
   
   4   FORMAT="path"
   
   6   for ARG in $@
   7   do
   8           if [ '`echo $ARG | cut -c1`" = "-" ]
   9             then case $ARG in
   10                 -l) FORMAT="ls"
   11                     shift;;
   12                 -s) FORMAT="set"
   13                     set "1";;
   14                 *)  echo $0: arg error"                        >&2
   15                     echo "usage: $0 [-l] [-s] file [file ...]" >&2
   16                     exit 1;;
   17                 esac
   18          fi
   19  done
   
   21  IFS="${IFS}:"
   
   23  for FILE in $@
   24  do
   25           for DIR in $PATH
   26           do
   27                   case $FORMAT in
   28                   path) if [ -f $DIR/$FILE ]
   29                            then echo $DIR/$FILE
   30                         fi;;
   31                   ls)   if [ -f $DIR/$FILE ]
   32                           then ls -l $DIR/$FILE
   33                         fi;;
   34                   set)  echo "\n:::::::::::::::::::"
   35                         echo "$DIR"
   36                         echo "::::::::::::::::::::"
   37                         ls -al $DIR | grep "^[^ ]*s[^ ]*";;
   38                   esac
   39            done
   40  done
ПЕРЕМЕННЫЕ СРЕДЫ ВЫПОЛНЕНИЯ
ARG Содержит каждый аргумент командной строки
DIR Элемент с именем каталога в переменной PATH
FILE Содержит имя каждого файла в командной строке
FORMAT Тип требуемого формата выходных данных
IFS Переменная shell'а, разделитель полей
PATH Переменная shell'а, пути к каталогам исполняемых модулей
ОПИСАНИЕ

ЗАЧЕМ НАМ НУЖЕН КОМАНДНЫЙ ФАЙЛ paths?

В нашей среде интерпретатора shell переменная с именем PATH содержит имена каталогов, отделенные друг от друга символами двоеточия (:). Каждый раз, когда вы вводите команду после приглашения shell'а, интерпретатор shell, начиная с первого каталога, указанного в переменной PATH, смотрит, находится ли введенная вами команда в этом каталоге. Если да, то команда выполняется. Если нет, то shell идет в следующий каталог, указываемый переменной PATH, и так далее, пока не будут проверены все каталоги. Если команда все же не будет найдена, то вы получите следующее сообщение об ошибке:

   |
   |    $ whatchamacallit
   |    sh: whatchamacallit: not found
   |
   |

Такой поиск команды осуществляется автоматически, но сама система не сообщает вам, ГДЕ размещена команда. Нам необходима утилита, которая ищет и выводит на экран маршрут к указанному файлу. Имея такую утилиту, вы можете использовать кратчайшие пути получения того, что вам нужно, и выполнять множество различных трюков. Вы можете комбинировать подобную команду с другими командами для создания гораздо более мощных средств. С маршрутом можно также комбинировать команды more, ls, file и cd системы UNIX. Возможно, вы обнаружите и другие команды по мере экспериментирования.

Команда, несколько похожая на ту, которую мы ищем, существует где-то в мире системы UNIX Systev V. Например, в системе AT&T это команда where. В системе UNIX Berkeley это команда which (текст на языке Си-shell'а) или whereis (исполняемая программа). Whereis дает дополнительную информацию, такую как место размещения файлов с исходными текстами (в каталоге /usr/src). Увидев, как мы создаем нашу собственную команду поиска маршрута, вы можете модифицировать ее для обеспечения работы с особенностями некоторых других команд и приспособить такие вещи к вашим нуждам.

Прежде чем мы удовлетворим свои прихоти, давайте бегло глянем на команду path, более простую, чем paths. Вся программа выглядит примерно так:

   IFS="${IFS}:"
   for FILE in $@
   do
      for DIR in $PATH
      do
          if [ -f $DIR/$FILE ]
            then  echo $DIR/$FILE
          fi
      done
   done

Основная идея очень проста. Сперва мы добавляем двоеточие (:) к разделителю полей. Нам необходимо сохранить значения, принятые по умолчанию (пробелы, табуляции, символы новой строки), так, чтобы мы могли все-таки обрабатывать командную строку с пробелами в качестве символов-разделителей. Символ : дает нам возможность отдельно рассматривать каждый маршрут, хранимый в переменной PATH.

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

Если ваша переменная PATH выглядит так:

    PATH=.:/bin:/usr/bin:/etc/:$HOME/bin

то внутренний цикл выполнит пять итераций в таком порядке: ., /bin, /usr/bin, /etc и, наконец, $HOME/bin. Если бы запрос имел вид "path ll" для поиска утилиты, которую мы создадим позже в этой главе, то результат мог бы выглядеть так:

   |
   |    /usr/bin/ll
   |    /usr/russ/bin/ll
   |
   |

Это значит, что команда ll была найдена в двух местах из вашего набора маршрутов поиска.

ЧТО ДЕЛАЕТ paths?

Теперь, когда мы знаем, как работает более простая команда path, мы можем по достоинству оценить дополнительные возможности специальной команды получения маршрута - команды paths. Paths имеет три основные функции. Она может выполняться как основная команда path, которую мы уже рассмотрели, и давать полное маршрутное имя исполняемого модуля. Она может выдавать маршрут файла в длинном формате. Она также может выдать список всех файлов с установленным пользовательским идентификатором (setuid bit files), которые есть в ваших маршрутных каталогах. (См. главу 8, где описаны биты setuid.)

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

    paths [-l] file [file ...]

как, например, в командах "paths ls who date" или "paths -l ll". Для поиска файлов с установленным пользовательским идентификатором (setuid files) не нужно указывать имена файлов в командной строке. Вся команда должна быть такой:

    paths -s

Формат setuid и форматы выдачи маршрута являются взаимоисключающими, поскольку предполагается, что вы хотите узнать от компьютера, какие и где находятся файлы, а не отгадывать имена файлов.

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

ПРИМЕРЫ
   1.  $ paths ls more who paths
       /bin/ls
       /usr/bin/more
       /bin/who
       /usr/russ/bin/paths

Поиск маршрутов к командам ls, more, who, paths. При выводе указываются полные абсолютные маршрутные имена. Обратите внимание, что в конце имени каждого файла печатается символ новой строки, чтобы получить распечатку, в которой каждое имя файла стоит в отдельной строке.

    2.  $ more `paths gettydefs termcap paths`

Если ваша переменная PATH содержит каталог /etc, то этот пример будет работать. Если нет, то первые два файла не будут найдены. Сначала запускается команда paths, и ее вывод помещается на свое место в командной строке команды more. Когда запускается команда more, она не знает, что ее аргументы получены от другой команды. После завершения работы команды paths команда more принимает вид:

    more /etc/gettydefs /etc/termcap/usr/russ/bin/paths

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

    3.  $ ll `paths ll`

В этом примере в длинном формате выводятся файлы с именами ll, которые найдет path. (Мы представим нашу версию команды ll несколько позже в этой же главе.) Как и в предыдущем случае, сначала генерируется информация о маршруте, затем она помещается в командную строку, а затем запускается команда ll.

    4.  $ m `paths paths`

В данном примере генерируется маршрутное имя самого командного файла paths и передается программе m, которая использует команду more для распечатки. (Командный файл m мы также покажем вам позже.)

ПОЯСНЕНИЯ

В строке 4 инициализируется переменная FORMAT, указывая маршрутный тип поиска. Выполняется действие по умолчанию, точно такое же, как в командном файле path, который мы рассмотрели ранее.

В строках 6-19 все аргументы командной строки проверяются на корректность. Критерием того, что аргумент есть опция, является дефис в роли первого символа. Заметим, что здесь не разрешено использование синтаксиса "-xyz". Это заставляет вас пользоваться синтаксисом "-x -y -z". Хотя этот момент может показаться несущественным, на самом деле он важен. Всегда нужно достигать компромисса между быстрой разработкой командного файла при согласии на недостатки жесткого синтаксиса - и разрешением гибкого формата за счет дополнительных усилий по кодированию и отладке и за счет более медленного выполнения. Ваш выбор зависит от ваших приоритетов, от количества людей, использующих ваше инструментальное средство, и от того, насколько критична скорость выполнения. Конечно, если скорость критична, вы, вероятно, захотите использовать каким-то образом язык Си. Мы оставляем обработку конкатенированных опций в качестве упражнения для читателя.

Цикл for проходит по всем позиционным параметрам. Если первым символом аргумента является "-", то он сверяется со списком допустимых аргументов с помощью оператора case в строках 9-17. Опция "-l" изменяет переменную формата, после чего убирается из рассмотрения. Это делается для освобождения этой позиции, чтобы конечным результатом были просто имена файлов в командной строке.

Опция "-s" также изменяет переменную формата. Однако, вместо того, чтобы убрать опцию из командной строки, она ликвидирует всю командную строку и заменяет ее символом "l". Это заставляет цикл for проходить только одну итерацию, так как в командной строке теперь только один параметр. Благодаря такому обращению с командной строкой, нам не нужен другой цикл: мы можем использовать тот же цикл, что и в определении маршрута, без всяких модификаций. Поскольку после опции s не ожидается никаких имен файлов, мы больше не хотим рассматривать командную строку.

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

В строке 21 мы добавляем символ двоеточия (:) к другим символам разделителя полей. Мы должны именно добавить двоеточие, а не превратить разделитель полей только в двоеточие. Если бы мы сделали последнее, то это запутало бы разбор имен файлов в командной строке. Основной цикл представлен в строках 23-40. Это двойной цикл for. Внешний цикл проходит по каждому файлу в командной строке, а внутренний цикл обрабатывает каждый каталог, указанный в вашей переменной PATH. Обратите внимание, что внешний цикл идет по именам файлов, а не по записям каталогов. Если бы мы выбрали второе, то в распечатке нарушился бы порядок имен файлов, поскольку поиск шел бы сначала по каталогам.

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

Опция ls есть дополнение, которое сокращает объем работы при вызове. Наличие комбинации поиска и команды ls освобождает того, кто вызывает этот командный файл от необходимости применять команду подстановки. Старая и новая команды выглядят примерно так:

    ll `path ll`

Находит путь к ll, а затем запускает на нем команду ls -l.

    paths -l ll

Находит путь и вместо того, чтобы его напечатать, выполняет команду ls -l применительно к этому пути.

Формат setuid в строке 34 прощается с подходом "один файл за один раз" и включает каталоговую машину. Поскольку внешний цикл установлен на одну итерацию, внутренний цикл становится главным. Для каждого каталога, указанного в PATH, печатаются оформление из двоеточий и имя каталога. Это делает распечатку приятной, информативной и наглядной. Ключевой командой является комбинация ls-grep. Каждое имя файла в каталоге распечатывается в длинном формате, затем просматривается бит установки пользовательского идентификатора. Модель такова, что команда ls -al $DIR печатает следующее:

   |
   |  -rws--x--x   1 root   bin       16235 Sep 13  1985 /bin/su
   |
   |

Аргумент "^[^ ]*s[^ ]*" означает поиск от начала строки символа, отличного от пробела, за которым следует один или более символов, отличных от пробела, затем символ s и затем один или более символов, отличных от пробела. Это выражение ограничивает поиск битами прав доступа в начале строки. Если имеется символ s где-либо в правах доступа (либо в пользовательском идентификаторе процесса, либо в групповом идентификаторе процесса), то команда grep отрабатывает успешно и печатается вся строка.

Такой вид поиска установленного пользовательского идентификатора несколько "легковесен" в том смысле, что поиск ведется только согласно переменной PATH, которая у вас есть. Файлы с установленным пользовательским идентификатором могут находиться в каталогах, которые не указаны в PATH. Однако в такой реализации данная опция обеспечивает быстрое обращение к вашим локальным файлам с установленным пользовательским идентификатором.

ВОЗМОЖНЫЕ МОДИФИКАЦИИ

Данный командный файл открыт для многих различных видов модификации. Поиск полного имени файла является фундаментальной задачей программного обеспечения по сопровождению файлов. Эта возможность позволяет нам полагаться на саму программу paths или использовать paths в качестве куска более объемной программы.

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

2.2. ВЫВОД ИНФОРМАЦИИ

2.2.1. lc - вывод файловой информации на экран по столбцам


    ИМЯ:        lc

lc Выдает список файлов в колоночном формате

НАЗНАЧЕНИЕ

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

ФОРМАТ ВЫЗОВА
    lc [-m] [ls options] file [file ...]
ПРИМЕР ВЫЗОВА
    lc -R $HOME

Выдает список всех файлов во всех подкаталогах моего регистрационного каталога.

ТЕКСТ ПРОГРАММЫ
   1   :
   2   # @(#) lc v1.0   List files in a column   Author: Russ Sage
   2а                    Выводит список файлов в колоночном виде
   
   4   if [ "$1" = "-m" ]
   5     then  MORE="| /usr/bin/more"
   6           shift
   7     else  MORE=""
   8   fi
   
   10   eval "/bin/ls -a $@ | /bin/pr -5t" $MORE   # pre System V
   11   eval /bin/ls -aCF $@ $MORE                 # System V
ПЕРЕМЕННЫЕ СРЕДЫ ВЫПОЛНЕНИЯ

MORE Содержит программный канал к команде more

ОПИСАНИЕ

Зачем нам нужен командный файл lc?

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

Как видно из предыдущего листинга, lc имеет две формы. Одна предназначена для систем, более ранних, чем System V, а другая - для System V и последующих версий UNIX. Причина в том, что System V версии 2 имеет новую команду ls, которая делает именно то, что мы хотим. Система Berkeley также имеет версию команды ls, которая по умолчанию использует несколько колонок при выводе на терминал. Но для XENIX и ранних версий System V мы должны делать это сами. Дело в том, что хотя в вашей версии UNIX, XENIX или чего-либо еще могут отсутствовать команды, имеющиеся в других версиях, вы обычно можете построить то, что вам нужно. Это может потребовать определенных усилий, и ваши программы могут работать не так быстро и не так эффективно, но вы МОЖЕТЕ получить нужное средство.

Пользователям интерпретаторов csh и последнего sh, имеющего функции, видимо, лучше бы заменить весь этот сценарий на то, чтобы сделать lc псевдонимом (alias). Использовать возможность введения псевдонимов, чтобы присвоить имя любой корректной командной строке UNIX (например, вызову команды ls с указанными опциями). Это легче, чем писать командный файл, но ограничивает вас необходимостью работать с уже имеющимися командами или опциями. Это быстрее, так как не создается никаких дополнительных процессов.

При работе со старым интерпретатором sh мы должны пройти через обычную процедуру изготовления командного файла и размещения его в каталоге bin. С другой стороны, SCO XENIX System V решает эту проблему, связывая эти же имена (lc, lf, l) с обычной командной ls и используя вызывающее имя для определения формы распечатки.

Итак, зачастую имеется много альтернатив. Мастера UNIX, сталкиваясь с какой-либо проблемой, не борются с ней с помощью Си или командного файла интерпретатора shell. Поскольку они знакомы с существующими ресурсами системы UNIX, они могут рассмотреть проблему и выбрать стратегию, использующую наименее сложное средство, выполняющее данную работу с приемлемым уровнем производительности. В порядке возрастания сложности, это могут быть непонятная, но существующая команда и/или опция, псевдоним, командный файл интерпретатора shell или программа на языке Си.

Что делает lc?

Общий подход к разработке этой команды заключается в том, чтобы собрать вместе некоторые опции и сделать новую команду с более мощным интерфейсом. Чтобы достичь этой мощи, мы можем сделать пре- или постпроцессор для обычной команды системы UNIX.

Главная задача здесь - печать колонок, поэтому мы смотрим на опции команды ls, чтобы задействовать их. Конечно, мы включаем опцию -C. Какие еще опции ls нам нужны? Обычно UNIX не печатает файлы, имена которых начинаются с точек, например, .profile, если только вы не указываете ls -a. Это забывается при просмотре этих важных файлов, поэтому мы конструируем нашу команду так, чтобы она печатала их по умолчанию. Никакие файлы не скрываются от нас. Для пользователей System V и BSD (или для любого, кто имеет опцию -F), листинг улучшается за счет вывода "/" после имени каталога и "*" после исполняемого файла. Ранняя команда ls системы UNIX не имела возможности печатать в таком стиле. Отметим, что данное использование термина "исполняемый" означает показ того, что флаги прав доступа имеют бит "x", а не то, что это файл типа a.out с магическим числом. Это отличие важно тем, что делает наш командный файл более полезным.

Если ожидается длинная распечатка, как это бывает обычно для рекурсивных каталогов, то вы хотите иметь доступ к команде more. Мы встраиваем команду more так, чтобы ее можно было активировать с помощью опции -m. Опция -m должна быть первой опцией после имени команды, из-за способа, которым она проверяется внутри программы. Если она передается после первой опции, она переходит к команде UNIX ls и интерпретируется как печать в потоковом формате. Это такой формат, в котором все имена расположены в строках, разделенных запятыми (,). Как мы уже отмечали, вы можете сделать интерфейс этого командного файла более гибким за счет дополнительной работы над ним.

ПРИМЕРЫ
    1.  $ lc `path lc`

Получает полное имя для lc и распечатывает файловую информацию в виде колонок.

    2.  $ lc -m -R /

Печатает колоночный список ВСЕХ файлов в системе, рекурсивно проходя вниз по иерархии системного дерева и пропуская распечатку через команду more.

Еще один маленький фокус: этот синтаксис был использован для создания другой команды, названной expose. Командная строка "lc -m -R $@" давала бы рекурсивный список всех файлов в любом каталоге по вашему выбору в приятном постраничном формате.

    3.  $ lc -m -R /usr/lib

Рекурсивно распечатывает список всех файлов во всех каталогах, начиная с /usr/lib, и пропускает листинг через команду more.

    4.  $ lc -m . | more

Выдает список файлов в текущем каталоге и пропускает листинг через команду more, а затем снова пропускает все через more. Работает ли это ? Никоим образом. Возникает полная путаница, и клавиша прерывания обычно является наилучшим способом выхода из данной ситуации.

ПОЯСНЕНИЯ

В строках 4-8 проверяется, является ли первым аргументом командной строки -m - опция команды more. Если эта опция найдена, то в переменную MORE заносится указание конвейера и команда more. Тем самым устанавливается постобработка, которую следует применить к выходу команды ls. Затем эта опция убирается из командной строки. Это делается для того, чтобы остаток командной строки можно было передать команде ls, не вызвав при этом нежелательных эффектов. Если первой опцией не является -m, переменной MORE присваивается нулевое значение, чтобы она впоследствии не влияла на командную строку.

Строка 10 - это командная строка, которую вы бы использовали на старой UNIX-машине типа Version 7 или System III. Она не имеет ни встроенной опции для печати символов косой черты (/) и звездочек (*), ни возможности печати в виде колонок. Вы должны пожертвовать первой возможностью, а распечатки в виде нескольких колонок можно получить с помощью команды pr системы UNIX. Команда pr использована с опцией "-5t", поэтому она печатает в пять колонок (что обычно приемлемо, но если встречаются длинные имена файлов, то пяти колонок может оказаться слишком много) и не печатает верхний и нижний колонтитулы. Благодаря отказу от колонтитулов, 24-строчный формат не слишком неудобен для вас.

Отметим, что здесь использована команда eval. Это специальная встроенная команда интерпретатора shell, которая выполняет перевычисление текущей строки, подлежащей выполнению. Интерпретатор shell повторно анализирует эту строку, чтобы раскрыть значение имен переменных в командной строке и обеспечить распознавание переменных как таковых. Здесь мы перевычисляем переменную MORE. Напомним, что мы поместили в эту переменную конвейер. Если мы не перевычислим командную строку, то команда pr попытается открыть файлы "|" и "more", которые не существуют. Для того, чтобы shell вместо этого воспринял эти символы как указания конвейеров и программ, и используется команда eval.

Строка 10 имеет еще одну особенность. В командной строке уже есть один конвейер. Откуда shell знает, трактовать ли символ "|" как имя файла или как конвейер? Благодаря тому, что аргумент команды eval заключен в кавычки. Это указывает команде eval сохранить все, что находится в кавычках, без изменений, но раскрыть значение переменной MORE и поместить его в конец командной строки, находящейся в кавычках. Несколько непонятно, но если вы думаете об этом пару лет, оно становится осмысленным.

Для тех из вас, кто имеет новую команду ls (System V, версия 2 или BSD 4.2), не требуется два конвейера в команде. Как показывает строка 11, мы получаем подходящий колоночный формат из самой команды ls, вместе с показом всех файлов и специальными символами / и * для каталогов и исполняемых файлов. Обозначение $@ относится ко всему содержимому командной строки, т.е. к вашим дополнительным опциям команды ls и к именам файлов, список которых вы хотите распечатать. Поступая таким образом, мы создаем фундамент (опции a,C,F), а вы можете надстраивать его (используя опции R,t и т.д.). Скромный, но элегантный фокус заставить ls сообщить свои опции заключается в том, чтобы вызвать ее с неверной опцией. Большинство команд не используют опции z или ?, поэтому вызов "ls -z" или "ls -?" приведет к такому результату:

   |
   |   ls: illegal option -- z
   |   usage:  -1ACFRabcdfgilmnopqrstux [files]
   |

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

Вы обратили внимание, что все обычные команды системы UNIX, используемые в нашем командном файле, имеют полные маршрутные имена? Это может показаться несколько странным, но причина указания полных маршрутных имен в том, что когда shell запускает команду, он не должен возвращаться к анализу переменной PATH и искать, где расположена команда. Если вы обращаетесь к командам относительным способом, время поиска файлов представляет собой большие накладные расходы. Когда вы вызываете lc, интерпретатор shell ищет эту команду, затем lc вызывает ls, которую тоже нужно найти. Если после этого результаты пропускаются через more или pr, то требуется дополнительный поиск. А полные маршрутные имена распознаются интерпретатором shell сразу же (он видит, что первым символом является /), и нужная команда может быть вызвана быстро. Издержки на поиск - единственные издержки команды lc.

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

2.2.2. ll - вывод файловой информации в длинном формате


    ИМЯ:        ll

ll Выдает список файлов в длинном формате

НАЗНАЧЕНИЕ

Выдает список файлов в длинном формате (-l). Распечатку можно пропустить через команду more.

ФОРМАТ ВЫЗОВА
    ll [-m] [ls options] file [file...]
ПРИМЕР ВЫЗОВА

ll *.c Выдача списка файлов с исходными текстами на языке Си в длинном формате.

ТЕКСТ ПРОГРАММЫ
   1  :
   2  # @(#) ll v1.0   Long listing of files   Author: Russ Sage
   2а                   Выводит список файлов в длинном формате
   
   4  if [ "$1" = "-m" ]
   5    then MORE="| /usr/bin/more"
   6          shift
   7    else MORE=""
   8  fi
   
   10 eval /bin/ls -al $@ MORE
ПЕРЕМЕННЫЕ СРЕДЫ ВЫПОЛНЕНИЯ

MORE Содержит строку передачи результатов по конвейеру команде more

ОПИСАНИЕ

Зачем нам нужен командный файл ll?

Мотивы для создания команды ll те же, что мы обсудили ранее для команды lc. Мы можем использовать ll для нескольких целей. Она уменьшает количество требуемых нажатий на клавиши, позволяет избежать необходимости помнить специальные опции и вообще настраивает систему соответственно нашим требованиям вместо того чтобы нам приспосабливаться к системе.

Что делает ll?

Основой этой команды является известная команда "ls -l". Она, если вы помните, дает очень емкую информацию о каждом файле, включая права доступа, связи, имя владельца, размер и так далее. (Кстати, программисты, использующие язык Си, могут получить эту информацию при помощи системного вызова stat(2).) Поскольку такой список при наличии множества файлов может легко переполнить экран, то предоставляется опция -m. Она обеспечивает постраничный вывод с помощью команды more. Отметим, что если используется эта опция, то она должна стоять первой. Строка символов, соответствующая этой опции, удаляется командой shift, так что она не смешивается с именами файлов и обычными опциями команды ls, которые передаются как аргументы.

После опции -m (если она есть) ll допускает указание любых других допустимых опций команды ls. Можно также использовать любую комбинацию имен файлов. Здесь применимы обычные средства порождения имен файлов: * соответствует любым символам, ? - одному символу, а символы [] задают диапазон из некоторого набора символов. В итоге мы получили команду ls, которая по умолчанию работает как "ls -l", вызывает команду more с помощью одной опции вместо необходимости указания конвейера в командной строке и при этом сохраняет гибкость команды ls.

ПРИМЕРЫ
    1.  $ ll /etc/*mount*

Выводит список всех файлов в каталоге /etc, имена которых содержат в каком-либо месте слово mount (например, mount, umount, unmountable).

    2.  $ ll -i `who|awk '{print "/dev/" $2}'`

Сперва выполняется команда who, затем результат ее работы по конвейеру передается команде awk, которая вырезает имя устройства и приписывает ему префикс /dev/. В результате список полных маршрутных имен ко всем терминальным устройствам, зарегистрированным в настоящий момент, помещается в командную строку команды ls -li. В распечатке указана вся информация об индексном дескрипторе файла (inode) для каждого терминального устройства.

    3.  $ ll `kind -a /lib`

Выводит в длинном формате список всех файлов архива в каталоге /lib. Этот каталог содержит библиотеки компиляторов всех языков системы UNIX. (Команда kind, которая отбирает файлы по их типу, рассматривается в следующем разделе.)

    4.  $ ll -m -i /dev

Выводит всю обычную информацию плюс номер индексного дескриптора для всех файлов в каталоге /dev. Выдача на экран происходит с помощью команды more.

ПОЯСНЕНИЯ

Если первым позиционным параметром является -m, то в строке 4 инициализируется переменная MORE для подключения конвейера и программы /usr/bin/more. (Вопрос о том, почему используется абсолютное маршрутное имя, обсуждался в предыдущем разделе.) Затем символьная строка -m командой shift убирается из командной строки. Если же первой опцией не является -m, то переменная MORE устанавливается в нуль, чтобы не влиять на повторный разбор командной строки, выполняемый с помощью команды eval (строка 10).

В строке 10 команда eval использована для получения результирующей командной строки. Команда ls вызывается с опциями -al (выдача списка всех файлов в длинном формате), которые мы установили по умолчанию. Затем берутся аргументы командной строки (минус первый аргумент, если это был -m, который мы убрали командой shift). Этими аргументами могут быть дополнительные опции команды ls плюс имена файлов или каталогов. В конце строки значение переменной MORE обеспечивает конвейер с командой more, если была указана опция -m. В противном случае значение переменной MORE равно нулю и не оказывает никакого влияния на анализ содержимого командной строки.

Что произошло бы, если бы пользователь указал опцию -m в качестве второй (или последующей) опции? В этом случае опция -m передалась бы команде ls. Команда ls трактовала бы эту опцию как "потоковый вывод", а это совсем не то, что мы хотели. Однако команда ls была вызвана также с опцией -l, которая отменяет опцию -m в соответствии с текстом программы ls. Вы не получили бы вывод с помощью команды more, но ваши выходные данные по-прежнему были бы выведены в правильном формате.

Назад | Содержание | Вперед