Какой тип команды не обрабатывает процессор shell
При интерактивной работе с системой пользователь постоянно сталкивается с необходимостью отдавать ей команды. В CDE это можно делать, выбирая мышью требуемые пункты меню . В текстовом окне или текстовом режиме команды набираются вручную в командной строке . После нажатия Enter команда должна быть интерпретирована и синтаксически проанализирована (где – имя программы , где – ключи, где – аргументы, где – спецсимволы ). Затем будут запущены один или несколько процессов.
В UNIX эту работу выполняет программа , которая называется командным процессором ( shell ). Иногда командный процессор называют шеллом (это – просто калька с английского) или интерпретатором команд (а это – неточно, потому что круг задач командного процессора шире, чем интерпретация команд).
Существует несколько широко распространенных командных процессоров и еще несколько малораспространенных, специфичных для конкретных вариантов UNIX . В Solaris принято использовать ksh , csh или bash .
Первый в мире UNIX командный интерпретатор в 1976 году написал Стив Баурн (Steve Bourne), когда он работал в Bell Laboratories в AT&T. ( По другим данным, Стив написал его в 1974 году.) Через некоторое время в University of California Berkeley был написан C- shell ( csh , произносится " си шелл"), а потом число разных командных процессоров стало быстро расти. Самыми популярные из них сейчас – это Bourne again shell ( bash ), разработанный в рамках проекта GNU и Korn shell ( ksh ) Дэвида Корна (David Korn).
С- shell был разработан студентом Университета в Беркли (University of California Berkeley) Биллом Джоем ( Bill Joy), который по окончании Berkeley основал компанию Sun Microsystems . Еще Билл Джой написал самый известный в UNIX редактор vi и был одним из авторов первой версии BSD UNIX .
В конце 1970-х годов был написан tcsh, расширение csh , совместимое с ним по командам, макроопределениям и синтаксису языка скриптов . Кен Грир (Ken Greer) начал работу над tcsh в Университете Карнеги-Мелон (Carnegie-Mellon University), а продолжил ее Пол Плэйсвэй (Paul Placeway) в восьмидесятые годы в Университете Огайо (Ohio State ). Основные отличия tcsh от csh сводятся к усовершенствованию редактирования командной строки и ряду дополнений в помощь создателям скриптов (например, переменные среды окружения, создаваемые только для чтения). В последних версиях UNIX csh обычно является символической ссылкой на tcsh, а оригинальный csh в поставку не включается, чтобы не шокировать пользователей пещерным уровнем редактирования командной строки .
В Solaris по умолчанию устанавливаются несколько командных процессоров , в том числе sh, csh , tcsh, bash и другие; командным процессором по умолчанию является sh.
Командный процессор призван выполнять в системе нижеперечисленные задачи:
- интерпретация команд пользователя, в том числе разбор командной строки ;
- запуск программ;
- организация перенаправления потоков между процессами;
- интерпретация языка скриптов и их выполнение;
- управление заданиями ;
- интерпретация шаблонов имен файлов;
- подстановка имен файлов в командную строку .
Некоторые командные процессоры поддерживают не все эти функции (см. таблицу 12.2).
Запуск командного процессора
Командный процессор запускается либо при входе пользователя в систему (и в дальнейшем пользователь отдает команды в его командной строке), либо из какой-либо программы ( по команде пользователя). Частным случаем является запуск командного процессора из другого командного процессора . Например, вы работаете в sh и желаете получить более удобные средства редактирования командной строки ; для этого вызывается bash . Тогда вы просто набираете команду
и оказываетесь в среде свежезапущенного командного процессора bash . При этом обычно меняется вид приглашения командной строки .
Каждый командный процессор при запуске пытается выполнить свои стартовые файлы, вначале системные (общие для всех пользователей), а затем пользовательские. Общие лежат в /etc , индивидуальные – в домашнем каталоге пользователя . Если командный процессор запускается при входе пользователя в систему (в таком случе он называется login shell , дословно – командный процессор , запущенный при входе в систему ), то после стартовых файлов он выполняет еще и login -файлы в том же порядке: сначала общий login - файл из /etc , затем – индивидуальный, из домашнего каталога. Login -файлы – это тоже стартовые файлы командного процессора ; все стартовые файлы фактически представляют собой скрипты на языке командного процессора и служат для инициализации среды окружения командного процессора для конкретного пользователя. Настройка командного процессора для пользователя позволяет творить чудеса: задать короткие псевдонимы для длинных часто используемых команд и т.п.
Некоторые командные процессоры при входе в систему выполняют сначала login -файлы, а затем – стартовые файлы; это зависит от того, как они были скомпилированы.
Другие командные процессоры не выполняют никакие стартовые файлы иначе, как при входе пользователя в систему. У командного процессора обычно есть ключ , который можно дать, чтобы сымитировать вход в систему и заставить его выполнить login -файлы.
Командный процессор bash , в отличие от других, использует более сложный алгоритм выполнения стартовых и login -файлов. Если он запущен как login shell , то выполняет /etc/ profile , если такой файл есть. Затем делается попытка выполнить ~/.bash_profile . Если такого файла нет, bash пытается выполнить файл ~/.bash_login , а если нет и такого файла, то выполняется ~/. profile . Если bash запущен не как login shell , то при старте он выполняет только файл ~/.bashrc . Если же bash был запущен как sh (т.е. 9sh является символьной ссылкой на bash ), то при старте он ведет себя так же, как и sh .
История команд
Все командные процессоры запоминают введенные пользователем команды (их список называется историей команд ). Во время сеанса работы командный процессор хранит историю команд в памяти, а по окончании работы записывает их в файл на диск . Файл истории команд хранится в домашнем каталоге пользователя . В sh, csh , tcsh он называется ~/. history , в bash – ~/.bash_history , в ksh – ~/.shhistory , а в бесплатной версии Korn Shell ( public domain Korn shell – pdksh) его по умолчанию нет вообще.
Многие командные процессоры позволяют повторить вызов ранее введенной команды по ее номеру или начальным буквам. О том, как это делать, подробнее рассказано ниже в разделе "повторение ранее введенных команд".
Существование файла истории команд может привести к уязвимости вашей системы. Имейте в виду, что по умолчанию он может быть доступен для чтения не только тому, кто вводил команды, но и другим пользователям. В этом случае следует избегать ввода каких бы то ни было паролей в командной строке . Например, возможно вызвать веб-обозреватель lynx или программу доступа к серверу баз данных mysql , указывая пароль в командной строке :
Так как эти команды сохранятся в файле истории вместе с другими, кто-то потом сможет прочесть их и узнать некоторые из ваших паролей.
Файл истории команд ограничен по размеру. По умолчанию, bash хранит 500 команд, tcsh – 1000, csh – 100, sh – в зависимости от версии. Часто sh не создает файл . history вовсе и дает доступ только к командам, которые были введены в течение текущего сеанса работы с ним. Можно изменить число хранимых команд, указав иное значение переменной , в которой оно хранится.
В этом разделе кратко рассматриваются главные детали системы UNIX, в частности файловая система, среда выполнения процессов и элементы структурных блоков (например, каналы). Подробное исследование взаимодействия этих деталей с ядром содержится в последующих главах.
1.3.1 Файловая система
- иерархической структурой,
- согласованной обработкой массивов данных,
- возможностью создания и удаления файлов,
- динамическим расширением файлов,
- защитой информации в файлах,
- трактовкой периферийных устройств (таких как терминалы и ленточные устройства) как файлов.
Файловая система организована в виде дерева с одной исходной вершиной, которая называется корнем (записывается: "/"); каждая вершина в древовидной структуре файловой системы, кроме листьев, является каталогом файлов, а файлы, соответствующие дочерним вершинам, являются либо каталогами, либо обычными файлами, либо файлами устройств. Имени файла предшествует указание пути поиска, который описывает место расположения файла в иерархической структуре файловой системы. Имя пути поиска состоит из компонент, разделенных между собой наклонной чертой (/); каждая компонента представляет собой набор символов, составляющих имя вершины (файла), которое является уникальным для каталога (предыдущей компоненты), в котором оно содержится. Полное имя пути поиска начинается с указания наклонной черты и идентифицирует файл (вершину), поиск которого ведется от корневой вершины дерева файловой системы с обходом тех ветвей дерева файлов, которые соответствуют именам отдельных компонент. Так, пути "/etc/passwd", "/bin/who" и "/usr/src/cmd/who.c" указывают на файлы, являющиеся вершинами дерева, изображенного на Рисунке 1.2, а пути "/bin/passwd" и "/usr/ src/date.c" содержат неверный маршрут. Имя пути поиска необязательно должно начинаться с корня, в нем следует указывать маршрут относительно текущего для выполняемого процесса каталога, при этом предыдущие символы "наклонная черта" в имени пути опускаются. Так, например, если мы находимся в каталоге "/dev", то путь "tty01" указывает файл, полное имя пути поиска для которого "/dev /tty01".
Программы, выполняемые под управлением системы UNIX, не содержат никакой информации относительно внутреннего формата, в котором ядро хранит файлы данных, данные в программах представляются как бесформатный поток байтов. Программы могут интерпретировать поток байтов по своему желанию, при этом любая интерпретация никак не будет связана с фактическим способом хранения данных в операционной системе. Так, синтаксические правила, определяющие задание метода доступа к данным в файле, устанавливаются системой и являются едиными для всех программ, однако семантика данных определяется конкретной программой. Например, программа форматирования текста troff ищет в конце каждой строки текста символы перехода на новую строку, а программа учета системных ресурсов acctcom работает с записями фиксированной длины. Обе программы пользуются одними и теми же системными средствами для осуществления доступа к данным в файле как к потоку байтов, и внутри себя преобразуют этот поток по соответствующему формату. Если любая из программ обнаружит, что формат данных неверен, она принимает соответствующие меры.
Каталоги похожи на обычные файлы в одном отношении; система представляет информацию в каталоге набором байтов, но эта информация включает в себя имена файлов в каталоге в объявленном формате для того, чтобы операционная система и программы, такие как ls (выводит список имен и атрибутов файлов), могли их обнаружить.
Права доступа к файлу регулируются установкой специальных битов разрешения доступа, связанных с файлом. Устанавливая биты разрешения доступа, можно независимо управлять выдачей разрешений на чтение, запись и выполнение для трех категорий пользователей: владельца файла, группового пользователя и прочих. Пользователи могут создавать файлы, если разрешен доступ к каталогу. Вновь созданные файлы становятся листьями в древовидной структуре файловой системы.
Для пользователя система UNIX трактует устройства так, как если бы они были файлами. Устройства, для которых назначены специальные файлы устройств, становятся вершинами в структуре файловой системы. Обращение программ к устройствам имеет тот же самый синтаксис, что и обращение к обычным файлам; семантика операций чтения и записи по отношению к устройствам в большой степени совпадает с семантикой операций чтения и записи обычных файлов. Способ защиты устройств совпадает со способом защиты обычных файлов: путем соответствующей установки битов разрешения доступа к ним (файлам). Поскольку имена устройств выглядят так же, как и имена обычных файлов, и поскольку над устройствами и над обычными файлами выполняются одни и те же операции, большинству программ нет необходимости различать внутри себя типы обрабатываемых файлов.
Например, рассмотрим программу на языке Си (Рисунок 1.3), в которой создается новая копия существующего файла. Предположим, что исполняемая версия программы имеет наименование copy. Для запуска программы пользователь вводит с терминала:
Операции open и creat возвращают целое значение, являющееся дескриптором файла и используемое программой в последующих ссылках на файлы. После этого программа вызывает подпрограмму copy, выполняющую в цикле операцию read (читать), по которой производится чтение в буфер порции символов из существующего файла, и операцию write (писать) для записи информации в новый файл. Операция read каждый раз возвращает количество прочитанных байтов (0 - если достигнут конец файла). Цикл завершается, если достигнут конец файла или если произошла ошибка при выполнении операции read (отсутствует контроль возникновения ошибок при выполнении операции write). Затем управление из подпрограммы copy возвращается в основную программу и запускается операция exit с кодом состояния 0 в качестве параметра, что указывает на успешное завершение выполнения программы.
Программа копирует любые файлы, указанные при ее вызове в качестве аргументов, при условии, что разрешено открытие существующего файла и создание нового файла. Файл может включать в себя как текст, который может быть выведен на печатающее устройство, например, исходный текст программы, так и символы, не выводимые на печать, даже саму программу. Таким образом, оба вызова:
являются допустимыми. Существующий файл также может быть каталогом. Например, по вызову:
копируется содержимое текущего каталога, обозначенного символом ".", в обычный файл "dircontents"; информация в новом файле совпадает, вплоть до каждого байта, с содержимым каталога, только этот файл обычного типа (для создания нового каталога предназначена операция mknod). Наконец, любой из файлов может быть файлом устройства. Например, программа, вызванная следующим образом:
читает символы, вводимые с терминала (файл /dev/tty соответствует терминалу пользователя), и копирует их в файл terminalread, завершая работу только в том случае, если пользователь нажмет . Похожая форма запуска программы:
вызывает чтение символов с терминала и их копирование обратно на терминал. Рисунок 1.3. Программа копирования файла
1.3.2 Среда выполнения процессов
Программой называется исполняемый файл, а процессом называется последовательность операций программы или часть программы при ее выполнении. В системе UNIX может одновременно выполняться множество процессов (эту особенность иногда называют мультипрограммированием или многозадачным режимом), при чем их число логически не ограничивается, и множество частей программы (такой как copy) может одновременно находиться в системе. Различные системные операции позволяют процессам порождать новые процессы, завершают процессы, синхронизируют выполнение этапов процесса и управляют реакцией на наступление различных событий. Благодаря различным обращениям к операционной системе, процессы выполняются независимо друг от друга.
Например, процесс, выполняющийся в программе, приведенной на Рисунке 1.4, запускает операцию fork, чтобы породить новый процесс. Новый процесс, именуемый порожденным процессом, получает значение кода завершения операции fork, равное 0, и активизирует операцию execl, которая выполняет программу copy (Рисунок 1.3). Операция execl загружает файл "copy", который предположительно находится в текущем каталоге, в адресное пространство порожденного процесса и запускает программу с параметрами, полученными от пользователя. В случае успешного выполнения операции execl управление в вызвавший ее процесс не возвращается, поскольку процесс выполняется в новом адресном пространстве (подробнее об этом в главе 7). Тем временем, процесс, запустивший операцию fork (родительский процесс), получает ненулевое значение кода завершения операции, вызывает операцию wait, которая приостанавливает его выполнение до тех пор, пока не закончится выполнение программы copy, и завершается (каждая программа имеет выход в конце главной процедуры, после которой располагаются программы стандартных библиотек Си, подключаемые в процессе компиляции). Например, если исполняемая программа называется run, пользователь запускает ее следующим образом:
Вообще использование обращений к операционной системе дает возможность пользователю создавать программы, выполняющие сложные действия, и как следствие, ядро операционной системы UNIX не включает в себя многие функции, являющиеся частью "ядра" в других системах. Такие функции, и среди них компиляторы и редакторы, в системе UNIX являются программами пользовательского уровня. Наиболее характерным примером подобной программы может служить командный процессор shell, с которым обычно взаимодействуют пользователи после входа в систему. Shell интерпретирует первое слово командной строки как имя команды: во многих командах, в том числе и в командах fork (породить новый процесс) и exec (выполнить порожденный процесс), сама команда ассоциируется с ее именем, все остальные слова в командной строке трактуются как параметры команды.
Shell обрабатывает команды трех типов. Во-первых, в качестве имени команды может быть указано имя исполняемого файла в объектном коде, полученного в результате компиляции исходного текста программы (например, программы на языке Си). Во-вторых, именем команды может быть имя командного файла, содержащего набор командных строк, обрабатываемых shell'ом. Наконец, команда может быть внутренней командой языка shell (в отличие от исполняемого файла). Наличие внутренних команд делает shell языком программирования в дополнение к функциям командного процессора; командный язык shell включает команды организации циклов (for-in-do-done и while-do-done), команды выполнения по условиям (if-then-else-fi), оператор выбора, команду изменения текущего для процесса каталога (cd) и некоторые другие. Синтаксис shell'а допускает сравнение с образцом и обработку параметров. Пользователям, запускающим команды, нет необходимости знать, какого типа эти команды.
Командный процессор shell ищет имена команд в указанном наборе каталогов, который можно изменить по желанию пользователя, вызвав shell. Shell обычно исполняет команду синхронно, с ожиданием завершения выполнения команды прежде, чем считать следующую командную строку. Тем не менее, допускается и асинхронное исполнение, когда очередная командная строка считывается и исполняется, не дожидаясь завершения выполнения предыдущей команды. О командах, выполняемых асинхронно, говорят, что они выполняются на фоне других команд. Например, ввод команды
вызывает выполнение системой программы, хранящейся в файле /bin/who (****) и осуществляющей вывод списка пользователей, которые в настоящий момент работают с системой. Пока команда who выполняется, командный процессор shell ожидает завершения ее выполнения и только затем запрашивает у пользователя следующую команду. Если же ввести команду
система выполнит программу who на фоне и shell готов немедленно принять следующую команду.
В среду выполнения каждого процесса в системе UNIX включается текущий каталог. Текущий для процесса каталог является начальным каталогом, имя которого присоединяется ко всем именам путей поиска, которые не начинаются с наклонной черты. Пользователь может запустить внутреннюю команду shell'а cd (изменить каталог) для перемещения по дереву файловой системы и для смены текущего каталога. Командная строка
делает текущим каталог "/usr/src/uts". Командная строка
делает текущим каталог, который на две вершины "ближе" к корню (корневому каталогу): параметр ".." относится к каталогу, являющемуся родительским для текущего.
Поскольку shell является пользовательской программой и не входит в состав ядра операционной системы, его легко модифицировать и помещать в конкретные условия эксплуатации. Например, вместо командного процессора Баурна (называемого так по имени его создателя, Стива Баурна), являющегося частью версии V стандартной системы, можно использовать процессор команд Си, обеспечивающий работу механизма ведения истории изменений и позволяющий избегать повторного ввода только что использованных команд. В некоторых случаях при желании можно воспользоваться командным процессором shell с ограниченными возможностями, являющимся предыдущей версией обычного shell'а. Система может работать с несколькими командными процессорами одновременно. Пользователи имеют возможность запускать одновременно множество процессов, процессы же в свою очередь могут динамически порождать новые процессы и синхронизировать их выполнение. Все эти возможности обеспечиваются благодаря наличию мощных программных и аппаратных средств, составляющих среду выполнения процессов. Хотя привлекательность shell'а в наибольшей степени определяется его возможностями как языка программирования и его возможностями в обработке аргументов, в данном разделе основное внимание концентрируется на среде выполнения процессов, управление которой в системе возложено на командный процессор shell. Другие важные особенности shell'а выходят за рамки настоящей книги (подробное описание shell'а см. в [Bourne 78]).
1.3.3 Элементы конструкционных блоков
выводит список всех файлов текущего каталога на устройство (в файл) стандартного вывода, а команда
переназначает выводной поток со стандартного вывода в файл "output" в текущем каталоге, используя вышеупомянутый системный вызов creat. Подобным же образом, команда
открывает (с помощью системного вызова open) файл "letter" в качестве файла стандартного ввода и пересылает его содержимое пользователю с именем "mjb". Процессы могут переназначать одновременно и ввод, и вывод, как, например, в командной строке:
Вторым конструкционным элементом является канал, механизм, обеспечивающий информационный обмен между процессами, выполнение которых связано с операциями чтения и записи. Процессы могут переназначать выводной поток со стандартного вывода на канал для чтения с него другими процессами, переназначившими на канал свой стандартный ввод. Данные, посылаемые в канал первыми процессами, являются входными для вторых процессов. Вторые процессы так же могут переназначить свой выводной поток и так далее, в зависимости от пожеланий программиста. И снова, так же как и в вышеуказанном случае, процессам нет необходимости знать, какого типа файл используется в качестве файла стандартного вывода; их выполнение не зависит от того, будет ли файлом стандартного вывода обычный файл, канал или устройство. В процессе построения больших и сложных программ из конструкционных элементов меньшего размера программисты часто используют каналы и переназначение ввода-вывода при сборке и соединении отдельных частей. И действительно, такой стиль программирования находит поддержку в системе, благодаря чему новые программы могут работать вместе с существующими программами.
Например, программа grep производит поиск контекста в наборе файлов (являющихся параметрами программы) по следующему образцу:
где "main" - подстрока, поиск которой производится в файлах a.c, b.c и c.c с выдачей в файл стандартного вывода тех строк, в которых она содержится. Содержимое выводного файла может быть следующим:
Программа wc с необязательным параметром -l подсчитывает число строк в файле стандартного ввода. Командная строка
вызовет подсчет числа строк в указанных файлах, где будет обнаружена подстрока "main"; выводной поток команды grep поступит непосредственно на вход команды wc. Для предыдущего примера результат будет такой:
Использование каналов зачастую делает ненужным создание временных файлов.
(****) Каталог "/bin" содержит большинство необходимых команд и обычно входит в число каталогов, в которых ведет поиск командный процессор shell.
Теперь у нас есть достаточно материала, чтобы перейти к объяснению принципов работы командного процессора shell. Сам командный процессор намного сложнее, чем то, что мы о нем здесь будем излагать, однако взаимодействие процессов мы уже можем рассмотреть на примере реальной программы. На Рисунке 7.28 приведен фрагмент основного цикла программы shell, демонстрирующий асинхронное выполнение процессов, переназначение вывода и использование каналов.
Shell считывает командную строку из файла стандартного ввода и интерпретирует ее в соответствии с установленным набором правил. Дескрипторы файлов стандартного ввода и стандартного вывода, используемые регистрационным shell'ом, как правило, указывают на терминал, с которого пользователь регистрируется в системе (см. главу 10). Если shell узнает во введенной строке конструкцию собственного командного языка (например, одну из команд cd, for, while и т.п.), он исполняет команду своими силами, не прибегая к созданию новых процессов; в противном случае команда интерпретируется как имя исполняемого файла.
Командные строки простейшего вида содержат имя программы и несколько параметров, например:
Shell "ветвится" (fork) и порождает новый процесс, который и запускает программу, указанную пользователем в командной строке. Родительский процесс (shell) дожидается завершения потомка и повторяет цикл считывания следующей команды.
Рисунок 7.28. Основной цикл программы shell (продолжение)
Если процесс запускается асинхронно (на фоне основной программы), как в следующем примере
shell анализирует наличие символа амперсанд (&) и заносит результат проверки во внутреннюю переменную amper. В конце основного цикла shell обращается к этой переменной и, если обнаруживает в ней признак наличия символа, не выполняет функцию wait, а тут же повторяет цикл считывания следующей команды.
Из рисунка видно, что процесс-потомок по завершении функции fork получает доступ к командной строке, принятой shell'ом. Для того, чтобы переадресовать стандартный вывод в файл, как в следующем примере
процесс-потомок создает файл вывода с указанным в командной строке именем; если файл не удается создать (например, не разрешен доступ к каталогу), процесс-потомок тут же завершается. В противном случае процесс-потомок закрывает старый файл стандартного вывода и переназначает с помощью функции dup дескриптор этого файла новому файлу. Старый дескриптор созданного файла закрывается и сохраняется для запускаемой программы. Подобным же образом shell переназначает и стандартный ввод и стандартный вывод ошибок.
Рисунок 7.29. Взаимосвязь между процессами, исполняющими командную строку ls -l|wc
Из приведенного текста программы видно, как shell обрабатывает командную строку, используя один канал. Допустим, что командная строка имеет вид:
После создания родительским процессом нового процесса процесс-потомок создает канал. Затем процесс-потомок создает свое ответвление; он и его потомок обрабатывают по одной компоненте командной строки. "Внучатый" процесс исполняет первую компоненту строки (ls): он собирается вести запись в канал, поэтому он закрывает старый файл стандартного вывода, передает его дескриптор каналу и закрывает старый дескриптор записи в канал, в котором (в дескрипторе) уже нет необходимости. Родитель (wc) "внучатого" процесса (ls) является потомком основного процесса, реализующего программу shell'а (см. Рисунок 7.29). Этот процесс (wc) закрывает свой файл стандартного ввода и передает его дескриптор каналу, в результате чего канал становится файлом стандартного ввода. Затем закрывается старый и уже не нужный дескриптор чтения из канала и исполняется вторая компонента командной строки. Оба порожденных процесса выполняются асинхронно, причем выход одного процесса поступает на вход другого. Тем временем основной процесс дожидается завершения своего потомка (wc), после чего продолжает свою обычную работу: по завершении процесса, выполняющего команду wc, вся командная строка является обработанной. Shell возвращается в цикл и считывает следующую командную строку.
При интерактивной работе с системой пользователь постоянно сталкивается с необходимостью отдавать ей команды. В CDE это можно делать, выбирая мышью требуемые пункты меню . В текстовом окне или текстовом режиме команды набираются вручную в командной строке . После нажатия Enter команда должна быть интерпретирована и синтаксически проанализирована (где – имя программы , где – ключи, где – аргументы, где – спецсимволы ). Затем будут запущены один или несколько процессов.
В UNIX эту работу выполняет программа , которая называется командным процессором ( shell ). Иногда командный процессор называют шеллом (это – просто калька с английского) или интерпретатором команд (а это – неточно, потому что круг задач командного процессора шире, чем интерпретация команд).
Существует несколько широко распространенных командных процессоров и еще несколько малораспространенных, специфичных для конкретных вариантов UNIX . В Solaris принято использовать ksh , csh или bash .
Первый в мире UNIX командный интерпретатор в 1976 году написал Стив Баурн (Steve Bourne), когда он работал в Bell Laboratories в AT&T. ( По другим данным, Стив написал его в 1974 году.) Через некоторое время в University of California Berkeley был написан C- shell ( csh , произносится " си шелл"), а потом число разных командных процессоров стало быстро расти. Самыми популярные из них сейчас – это Bourne again shell ( bash ), разработанный в рамках проекта GNU и Korn shell ( ksh ) Дэвида Корна (David Korn).
С- shell был разработан студентом Университета в Беркли (University of California Berkeley) Биллом Джоем ( Bill Joy), который по окончании Berkeley основал компанию Sun Microsystems . Еще Билл Джой написал самый известный в UNIX редактор vi и был одним из авторов первой версии BSD UNIX .
В конце 1970-х годов был написан tcsh, расширение csh , совместимое с ним по командам, макроопределениям и синтаксису языка скриптов . Кен Грир (Ken Greer) начал работу над tcsh в Университете Карнеги-Мелон (Carnegie-Mellon University), а продолжил ее Пол Плэйсвэй (Paul Placeway) в восьмидесятые годы в Университете Огайо (Ohio State ). Основные отличия tcsh от csh сводятся к усовершенствованию редактирования командной строки и ряду дополнений в помощь создателям скриптов (например, переменные среды окружения, создаваемые только для чтения). В последних версиях UNIX csh обычно является символической ссылкой на tcsh, а оригинальный csh в поставку не включается, чтобы не шокировать пользователей пещерным уровнем редактирования командной строки .
В Solaris по умолчанию устанавливаются несколько командных процессоров , в том числе sh, csh , tcsh, bash и другие; командным процессором по умолчанию является sh.
Командный процессор призван выполнять в системе нижеперечисленные задачи:
- интерпретация команд пользователя, в том числе разбор командной строки ;
- запуск программ;
- организация перенаправления потоков между процессами;
- интерпретация языка скриптов и их выполнение;
- управление заданиями ;
- интерпретация шаблонов имен файлов;
- подстановка имен файлов в командную строку .
Некоторые командные процессоры поддерживают не все эти функции (см. таблицу 12.2).
Запуск командного процессора
Командный процессор запускается либо при входе пользователя в систему (и в дальнейшем пользователь отдает команды в его командной строке), либо из какой-либо программы ( по команде пользователя). Частным случаем является запуск командного процессора из другого командного процессора . Например, вы работаете в sh и желаете получить более удобные средства редактирования командной строки ; для этого вызывается bash . Тогда вы просто набираете команду
и оказываетесь в среде свежезапущенного командного процессора bash . При этом обычно меняется вид приглашения командной строки .
Каждый командный процессор при запуске пытается выполнить свои стартовые файлы, вначале системные (общие для всех пользователей), а затем пользовательские. Общие лежат в /etc , индивидуальные – в домашнем каталоге пользователя . Если командный процессор запускается при входе пользователя в систему (в таком случе он называется login shell , дословно – командный процессор , запущенный при входе в систему ), то после стартовых файлов он выполняет еще и login -файлы в том же порядке: сначала общий login - файл из /etc , затем – индивидуальный, из домашнего каталога. Login -файлы – это тоже стартовые файлы командного процессора ; все стартовые файлы фактически представляют собой скрипты на языке командного процессора и служат для инициализации среды окружения командного процессора для конкретного пользователя. Настройка командного процессора для пользователя позволяет творить чудеса: задать короткие псевдонимы для длинных часто используемых команд и т.п.
Некоторые командные процессоры при входе в систему выполняют сначала login -файлы, а затем – стартовые файлы; это зависит от того, как они были скомпилированы.
Другие командные процессоры не выполняют никакие стартовые файлы иначе, как при входе пользователя в систему. У командного процессора обычно есть ключ , который можно дать, чтобы сымитировать вход в систему и заставить его выполнить login -файлы.
Командный процессор bash , в отличие от других, использует более сложный алгоритм выполнения стартовых и login -файлов. Если он запущен как login shell , то выполняет /etc/ profile , если такой файл есть. Затем делается попытка выполнить ~/.bash_profile . Если такого файла нет, bash пытается выполнить файл ~/.bash_login , а если нет и такого файла, то выполняется ~/. profile . Если bash запущен не как login shell , то при старте он выполняет только файл ~/.bashrc . Если же bash был запущен как sh (т.е. 9sh является символьной ссылкой на bash ), то при старте он ведет себя так же, как и sh .
История команд
Все командные процессоры запоминают введенные пользователем команды (их список называется историей команд ). Во время сеанса работы командный процессор хранит историю команд в памяти, а по окончании работы записывает их в файл на диск . Файл истории команд хранится в домашнем каталоге пользователя . В sh, csh , tcsh он называется ~/. history , в bash – ~/.bash_history , в ksh – ~/.shhistory , а в бесплатной версии Korn Shell ( public domain Korn shell – pdksh) его по умолчанию нет вообще.
Многие командные процессоры позволяют повторить вызов ранее введенной команды по ее номеру или начальным буквам. О том, как это делать, подробнее рассказано ниже в разделе "повторение ранее введенных команд".
Существование файла истории команд может привести к уязвимости вашей системы. Имейте в виду, что по умолчанию он может быть доступен для чтения не только тому, кто вводил команды, но и другим пользователям. В этом случае следует избегать ввода каких бы то ни было паролей в командной строке . Например, возможно вызвать веб-обозреватель lynx или программу доступа к серверу баз данных mysql , указывая пароль в командной строке :
Так как эти команды сохранятся в файле истории вместе с другими, кто-то потом сможет прочесть их и узнать некоторые из ваших паролей.
Файл истории команд ограничен по размеру. По умолчанию, bash хранит 500 команд, tcsh – 1000, csh – 100, sh – в зависимости от версии. Часто sh не создает файл . history вовсе и дает доступ только к командам, которые были введены в течение текущего сеанса работы с ним. Можно изменить число хранимых команд, указав иное значение переменной , в которой оно хранится.
При интерактивной работе с системой пользователь постоянно сталкивается с необходимостью отдавать ей команды. В CDE это можно делать, выбирая мышью требуемые пункты меню . В текстовом окне или текстовом режиме команды набираются вручную в командной строке . После нажатия Enter команда должна быть интерпретирована и синтаксически проанализирована (где – имя программы , где – ключи, где – аргументы, где – спецсимволы ). Затем будут запущены один или несколько процессов.
В UNIX эту работу выполняет программа , которая называется командным процессором ( shell ). Иногда командный процессор называют шеллом (это – просто калька с английского) или интерпретатором команд (а это – неточно, потому что круг задач командного процессора шире, чем интерпретация команд).
Существует несколько широко распространенных командных процессоров и еще несколько малораспространенных, специфичных для конкретных вариантов UNIX . В Solaris принято использовать ksh , csh или bash .
Первый в мире UNIX командный интерпретатор в 1976 году написал Стив Баурн (Steve Bourne), когда он работал в Bell Laboratories в AT&T. ( По другим данным, Стив написал его в 1974 году.) Через некоторое время в University of California Berkeley был написан C- shell ( csh , произносится " си шелл"), а потом число разных командных процессоров стало быстро расти. Самыми популярные из них сейчас – это Bourne again shell ( bash ), разработанный в рамках проекта GNU и Korn shell ( ksh ) Дэвида Корна (David Korn).
С- shell был разработан студентом Университета в Беркли (University of California Berkeley) Биллом Джоем ( Bill Joy), который по окончании Berkeley основал компанию Sun Microsystems . Еще Билл Джой написал самый известный в UNIX редактор vi и был одним из авторов первой версии BSD UNIX .
В конце 1970-х годов был написан tcsh, расширение csh , совместимое с ним по командам, макроопределениям и синтаксису языка скриптов . Кен Грир (Ken Greer) начал работу над tcsh в Университете Карнеги-Мелон (Carnegie-Mellon University), а продолжил ее Пол Плэйсвэй (Paul Placeway) в восьмидесятые годы в Университете Огайо (Ohio State ). Основные отличия tcsh от csh сводятся к усовершенствованию редактирования командной строки и ряду дополнений в помощь создателям скриптов (например, переменные среды окружения, создаваемые только для чтения). В последних версиях UNIX csh обычно является символической ссылкой на tcsh, а оригинальный csh в поставку не включается, чтобы не шокировать пользователей пещерным уровнем редактирования командной строки .
В Solaris по умолчанию устанавливаются несколько командных процессоров , в том числе sh, csh , tcsh, bash и другие; командным процессором по умолчанию является sh.
Командный процессор призван выполнять в системе нижеперечисленные задачи:
- интерпретация команд пользователя, в том числе разбор командной строки ;
- запуск программ;
- организация перенаправления потоков между процессами;
- интерпретация языка скриптов и их выполнение;
- управление заданиями ;
- интерпретация шаблонов имен файлов;
- подстановка имен файлов в командную строку .
Некоторые командные процессоры поддерживают не все эти функции (см. таблицу 12.2).
Запуск командного процессора
Командный процессор запускается либо при входе пользователя в систему (и в дальнейшем пользователь отдает команды в его командной строке), либо из какой-либо программы ( по команде пользователя). Частным случаем является запуск командного процессора из другого командного процессора . Например, вы работаете в sh и желаете получить более удобные средства редактирования командной строки ; для этого вызывается bash . Тогда вы просто набираете команду
и оказываетесь в среде свежезапущенного командного процессора bash . При этом обычно меняется вид приглашения командной строки .
Каждый командный процессор при запуске пытается выполнить свои стартовые файлы, вначале системные (общие для всех пользователей), а затем пользовательские. Общие лежат в /etc , индивидуальные – в домашнем каталоге пользователя . Если командный процессор запускается при входе пользователя в систему (в таком случе он называется login shell , дословно – командный процессор , запущенный при входе в систему ), то после стартовых файлов он выполняет еще и login -файлы в том же порядке: сначала общий login - файл из /etc , затем – индивидуальный, из домашнего каталога. Login -файлы – это тоже стартовые файлы командного процессора ; все стартовые файлы фактически представляют собой скрипты на языке командного процессора и служат для инициализации среды окружения командного процессора для конкретного пользователя. Настройка командного процессора для пользователя позволяет творить чудеса: задать короткие псевдонимы для длинных часто используемых команд и т.п.
Некоторые командные процессоры при входе в систему выполняют сначала login -файлы, а затем – стартовые файлы; это зависит от того, как они были скомпилированы.
Другие командные процессоры не выполняют никакие стартовые файлы иначе, как при входе пользователя в систему. У командного процессора обычно есть ключ , который можно дать, чтобы сымитировать вход в систему и заставить его выполнить login -файлы.
Командный процессор bash , в отличие от других, использует более сложный алгоритм выполнения стартовых и login -файлов. Если он запущен как login shell , то выполняет /etc/ profile , если такой файл есть. Затем делается попытка выполнить ~/.bash_profile . Если такого файла нет, bash пытается выполнить файл ~/.bash_login , а если нет и такого файла, то выполняется ~/. profile . Если bash запущен не как login shell , то при старте он выполняет только файл ~/.bashrc . Если же bash был запущен как sh (т.е. 9sh является символьной ссылкой на bash ), то при старте он ведет себя так же, как и sh .
История команд
Все командные процессоры запоминают введенные пользователем команды (их список называется историей команд ). Во время сеанса работы командный процессор хранит историю команд в памяти, а по окончании работы записывает их в файл на диск . Файл истории команд хранится в домашнем каталоге пользователя . В sh, csh , tcsh он называется ~/. history , в bash – ~/.bash_history , в ksh – ~/.shhistory , а в бесплатной версии Korn Shell ( public domain Korn shell – pdksh) его по умолчанию нет вообще.
Многие командные процессоры позволяют повторить вызов ранее введенной команды по ее номеру или начальным буквам. О том, как это делать, подробнее рассказано ниже в разделе "повторение ранее введенных команд".
Существование файла истории команд может привести к уязвимости вашей системы. Имейте в виду, что по умолчанию он может быть доступен для чтения не только тому, кто вводил команды, но и другим пользователям. В этом случае следует избегать ввода каких бы то ни было паролей в командной строке . Например, возможно вызвать веб-обозреватель lynx или программу доступа к серверу баз данных mysql , указывая пароль в командной строке :
Так как эти команды сохранятся в файле истории вместе с другими, кто-то потом сможет прочесть их и узнать некоторые из ваших паролей.
Файл истории команд ограничен по размеру. По умолчанию, bash хранит 500 команд, tcsh – 1000, csh – 100, sh – в зависимости от версии. Часто sh не создает файл . history вовсе и дает доступ только к командам, которые были введены в течение текущего сеанса работы с ним. Можно изменить число хранимых команд, указав иное значение переменной , в которой оно хранится.
Читайте также: