Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
ОСС.docx
Скачиваний:
8
Добавлен:
12.11.2019
Размер:
546.05 Кб
Скачать

Тема 5.5. Работа с Shell

Цель занятия: изучить основные возможности и команды интерпретатора Shell, уметь выполнять несколько задач одновременно, создавать скрипты shell, пользоваться командами обработки файлов.

План изложения материала

  1. стандартный вход и стандартный выход

  2. перенаправление входа-выхода

  3. использование конвейера

  4. выполнение нескольких задач одновременно

  5. основные команды shell

  6. сценарии (скрипты) shell

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

С некоторыми свойствами shell Вы уже знакомы.

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

Стандартный вход и стандартный выход.

Многие команды UNIX получают информацию с так называемого стандартного входа и посылают информацию на опять же так называемый стандартный выход. (Для них часто используются сокращения "stdin" и "stdout" соответственно). shell организует дело так, что стандартным входом служит клавиатура, а стандартным выходом - экран.

Рассмотрим, к примеру, использование команды cat. В случае, когда в качестве параметров заданы имена файлов, cat читает данные из файлов, имена которых определены в командной строке и посылает эти данные прямо на stdout. Поэтому при выполнении команды

cat .profile .kermrc

на экран будет выведено содержимое файла .profile, а следом за ним содержимое файла .kermrc.

Но если команде cat не заданы имена файлов в качестве параметров, то она читает данные со стандартного входа (клавиатуры) и посылает их на стандартный выход (экран). Вот пример. Введите команду

cat -u

Затем напечатайте

Hello there.

На экране появится

Hello there.

Напечатайте

Bye.

Вы получите ответ:

Bye.

Как видите, каждая строка, которую Вы напечатали, немедленно выдается командой cat на экран. При вводе со стандартного входа команда считает, что ввод закончен тогда, когда Вы нажимаете клавиши CTRL-d. Эта комбинация клавиш посылает команде сигнал EOT (End-Of-Text - конец текста). Поэтому нажмите CTRL-d (должно появиться новое приглашение на ввод $) и давайте рассмотрим другой пример.

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

Попробуйте так:

введите команду

sort

напечатайте с клавиатуры следующее (для перехода на новую строку используйте ENTER):

bananas

carrots

apples

Нажмите CTRL-d и Вы увидите измененный список.

apples

bananas

carrots

В конце появится новое приглашение на ввод команд $.

Перенаправление входа и выхода.

Теперь, предположим, что Вы хотите послать результат сортировки в файл, чтобы сохранить список планируемых покупок. shell дает возможность перенаправлять стандартный выход в файл, используя символ ">". Вот как это работает:

напечатайте команду sort и после символа > укажите имя файла, в который хотите сохранить результат выполнения команды (эта процедура должна быть Вам знакома - Вы уже создавали файлы подобным образом)

sort > shopping-list

Затем введите с клавиатуры список предполагаемых покупок (он попадет во входной поток команды, ведь по умолчанию входной поток - клавиатура):

bananas

carrots

apples

Снова нажмите CTRL-d.

Как Вы можете видеть, результат работы команды sort не отображается на экране (после нажатия клавиш CTRL-d сразу появляется новое приглашение), вместо этого он сохраняется в файле shopping-list (список покупок). Давайте проверим, действительно ли это так с помощью давно знакомой Вам команды cat:

cat shopping-list

Если Вы все сделали правильно, то содержимое файла shopping-list будет выглядеть следующим образом:

apples

bananas

carrots

Другой вариант - у Вас сохранен не отсортированный список в некотором файле. Один из способов его сортировки и сохранения такой - отсортировать файл с данным именем вместо получения содержимого файла со стандартного входа и перенаправить стандартный выход в файл.

Создайте файл pokupki, с помощью команды echo и перенаправления выходного потока:

echo " carrots

bananas

apples "> pokupki

для перевода строки используйте клавишу ENTER. ENTER не будет восприниматься как сигнал завершения ввода команды до тех пор, пока Вы не закроете кавычки. В начале каждой строки будет появляться повторное приглашение на ввод " > ".

После того как Вы создали файл, отсортируйте его и сохраните указанным выше способом:

sort pokupki > shopping-list

С помощью команды cat проверьте выполнение введенной команды:

cat shopping-list

Результат должен быть аналогичным предыдущему:

apples

bananas

carrots

То же самое можно сделать и по-другому. Перенаправлен может быть не только стандартный выход, но также и стандартный вход. Для этого следует использовать символ " < ". Введите, например, такую командную строку:

sort < pokupki

Команда sort выведет на экран (стандартный выход) отсортированные строки файла pokupki:

apples

bananas

carrots

Фактически sort < pokupki эквивалентно sort pokupki, но последний вариант позволяет продемонстрировать сказанное: sort < pokupki ведет себя так, словно читает данные файла pokupki со стандартного входа - клавиатуры (а не из заданного файла), в то время как на самом деле shell перенаправил данные файла в стандартный входной поток.

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

Использование конвейера.

Предыдущие примеры предполагали, что Вы ввели данные с клавиатуры своими собственными руками или извлекли их из файла. А что, если данные, которые Вы хотите отсортировать, являются выходными данными другой программы, например, такой как ls?

Попробуйте получить список файлов и подкаталогов Вашего личного каталога, отсортированный в порядке обратном к лексикографическому. Для подобной сортировки у команды sort существует опция -r. Но ее одной недостаточно - нужно использовать и возможности shell. Можно применить уже полученные Вами знания:

ls > file-list

Эта командная строка перенаправила выходной поток команды ls в файл file-list. При желании Вы можете убедиться в этом с помощью команд cat или more.

Вторая команда сортирует содержимое файла file-list в указанном порядке и выводит его на экран:

sort -r file-list

Такой способ не самый быстрый и требует создания временного файла для сохранения результата работы команды ls.

shell предоставляет и другой вариант - использование "конвейера" (pipeline). "Конвейер" - это замечательное свойство shell, которое позволяет связать последовательность команд в конвейер, где stdout первой команды посылается прямо на stdin второй команды и так далее.

В нашем примере необходимо направить стандартный выходной поток команды ls в стандартный входной поток команды sort. Символ "|" обозначает конвейер. Поэтому Вам достаточно ввести:

ls | sort -r

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

Другой полезный пример.

Команда

ls /usr/bin

выдает на дисплей длинный список имен файлов, большинство из которых слишком быстро исчезают с экрана, и Вы не успеваете прочитать их. Подключите к просмотру перечня имен файлов каталога /usr/bin команду more :

ls /usr/bin | more

Теперь Вы можете постранично листать файл в свое удовольствие.

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

ls | sort -r | head -1

где head -1 просто выдает первую строку (-1) получаемого входного потока (в данном случае это отсортированный в обратном порядке перечень имен файлов текущего каталога, выданных командой ls).

Перенаправление с добавлением.

Использование " > " для перенаправления выхода смертельно для файла, в который происходит перенаправление (если этот файл уже существует). Например,

ls > file-list

уничтожит прежнее содержимое файла file-list. Убедитесь, что теперь файл file-list содержит лишь список имен файлов и подкаталогов текущего каталога в алфавитном порядке, набрав команду

cat file-list

Если вместо ">" использовать символ перенаправления ">>", выходной поток будет добавлен к содержимому указанного файла (а не записан на место уже хранящейся в нем информации).

ls >> pokupki

добавит выходную информацию команды ls в файл pokupki. Это тоже стоит проверить, введя команду

cat pokupki

Имейте в виду, что перенаправления и конвейер - это средства, предоставляемые интерпретатором shell. Символы ">", ">>" и "|" - это синтаксис shell, и они не имеют никакого отношения к командам, как таковым.

Выполнение нескольких задач одновременно.

Вы уже знаете, что команды в UNIX заканчиваются либо точкой с запятой, либо символом перевода строки ENTER. В качестве еще одного символа, завершающего команду, применяют & . Действие его аналогично действию символа перевода строки и точки с запятой, но он еще и указывает интерпретатору, что не нужно ждать завершения команды.

Обычно & используется для запуска фоновых, долго выполняющихся команд, т.к. приглашение $ появляется на экране сразу, не дожидаясь окончания выполнения запущенной программы, и тем самым позволяет Вам продолжать ввод новых команд, пока фоновая программа выполняет свою работу. (В UNIX существует два способа выполнения программ: в оперативном и фоновом режимах. Оперативный режим означает, что Вы взаимодействуете с программой - она получает информацию с клавиатуры и посылает результаты на экран (кроме случаев, когда Вы сами перенаправляете вход или выход), и пока первая программа не закончит работу, запустить вторую нельзя. Фоновые программы не получают информации с терминала, а в случае необходимости вывода сообщения на экран делают это, не обращая внимания на существующий на экране текст.)

shell позволяет использовать скобки для группировки команд. А имея возможность группировать команды, Вы получаете интересные способы применения фоновых процессов (процесс - это выполняемая программа). Команда sleep ожидает указанное число секунд, прежде чем закончить свое выполнение:

sleep 5

До появления нового приглашения $ проходит 5 секунд.

Попробуйте такой вариант

(sleep 5; date) & date

На этот раз Вам ждать не придется - Вы увидите дату сразу, но это результат выполнения второй команды date. После даты появится приглашение - так что Вы можете продолжать ввод команд, и лишь затем через 5 секунд дата, выданная первой командой date.

Что происходит в системе при выполнении такой командной строки?

Фоновый процесс начинается, но сразу "засыпает"; тем временем вторая команда date выдает текущее время, а интерпретатор shell - приглашение для ввода новой команды.

Пятью секундами позже прекращается выполнение команды sleep, и первая команда date выдает новое время. (Разница между двумя значениями времени может и не равняться в точности пяти секундам, например, из-за загруженности машины.) Это удобный способ отложить запуск команды на будущее;

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

Давайте рассмотрим и такой пример:

(sleep 120; echo The tea is ready) & echo The tea will be ready through 2 minutes

После ввода этой командной строки не забудьте нажать клавишу ENTER.

Что произойдет в этом случае? Выполнение команд, заключенных в скобки будет переведено в фоновый режим. Вторая команда echo немедленно выдаст на экран сообщение: "The tea will be ready through 2 minutes" (Чай будет готов через 2 минуты). После чего в следующей строке появится системное приглашение, и Вы сможете продолжить выполнение команд. Через две минуты закончится фоновое выполнение команды sleep и команда echo выдаст на экран сообщение о том, что чай готов.

В этих примерах нужны скобки, так как приоритет & выше, чем ";".

Сценарии (скрипты) shell.

Создание новых команд.

Если Вы многократно выполняете одну и ту же последовательность команд, то shell предоставляет Вам возможность преобразовать ее в "новую" команду со своим именем и использовать как обычную команду, тем самым сократив объем постоянной печати.

Такая новая команда носит название сценария (скрипта) shell.

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

Если Вы создали сценарий, Вы должны убедиться, что имеете права на его выполнение (т.к. если вы создавали сценарий в редакторе, то он (обычно) не получает автоматически прав на выполнение).

Предположим, что Вам предстоит часто подсчитывать число пользователей с помощью конвейера.

who | wc -l

и для этой цели нужна новая программа nu.

Первым шагом должно быть создание обычного файла, содержащего 'who | wc -l'. Можно воспользоваться редактором vi или проявить изобретательность:

echo ' who | wc -l' >nu

Как отмечалось, интерпретатор является точно такой же программой, как редактор, who или wc; она называется sh. А коль скоро это программа, ее можно вызвать и переключить ее входной поток. Так что запустите интерпретатор с входным потоком, поступающим из файла nu, а не с терминала:

sh < nu

Проверьте результат выполнения команды, введя

who

Результат должен получиться таким же, каким он был при задании команды who | wc -l с терминала. Опять-таки, как и большинство программ, интерпретатор берет входной поток из файла, если он указан в качестве аргумента; Вы с тем же успехом могли задать:

sh nu

Однако досадно вводить " sh" каждый раз. Но если файл предназначен для выполнения и содержит текст, то интерпретатор считает, что он состоит из команд. Такие файлы называются командными. Поэтому все, что Вам нужно сделать, это объявить файл nu выполняемым, задав

chmod +х nu

а затем Вы можете вызывать его посредством nu.

Команда nu выполняется только в том случае, если она находится в текущем каталоге (при условии, конечно, что текущий каталог включен в PATH). Чтобы сделать команду nu выполняемой независимо от того, с каким каталогом Вы работаете, занесите ее в свой собственный каталог bin и добавьте /usr/ < имя пользователя > /bin к списку каталогов, в котором производится поиск команд для запуска:

cd; mkdir bin

эта командная строка создает каталог bin в Вашем личном каталоге.

mv nu bin

перемещает файл nu в каталог bin.

РАТН=/usr/ < имя пользователя > /bin:/usr/local/bin:/bin:/usr/bin

определяет новый путь поиска, причем таким образом, что сначала shell ищет команды именно в /usr/ < имя пользователя > /bin

Убедитесь, что Вы действительно изменили путь поиска команд для запуска, напечатав:

echo $ PATH

Проверьте, что nu исчезла из текущего каталога:

ls

А теперь запустите nu как обычную команду:

nu

Если Вы все сделали правильно, то shell должен найти и выполнить эту команду.

Аргументы команд.

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

Пусть Вы хотите создать программу с именем сх для установки права доступа к файлу на выполнение, так чтобы cx nu являлась сокращенной записью для chmod +х nu.

Вы уже знаете почти все, чтобы это сделать. Вам нужен файл сх, содержимое которого суть chmod +х < имя файла > . Единственное, что требуется выяснить - как сообщить команде сх имя файла, так как при каждом запуске сх оно будет иным.

У интерпретатора shell есть свойство, если он выполняет командный файл, то каждое вхождение символа $1 заменяется первым аргументом, каждое вхождение $2-вторым и т. д. до $9. Поэтому если файл сх содержит строку chmod +х $1, то при выполнении команды сх nu "$1" будет заменен первым аргументом "nu".

Рассмотрим всю последовательность операций:

echo 'chmod +х $1' >сх

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

sh сх сх

эта команда делает сам файл сх выполняемым.

echo echo Hi, there! >hello

создаете вспомогательный файл для проверки.

hello

пытаетесь выполнить созданный файл. Скорее всего, ответ должен быть отрицательным

hello: permission denied

т.к. при создании файла hello право на его выполнение не было установлено.

Исправьте это с помощью вновь созданной команды:

сх hello

Попробуйте снова выполнить вспомогательный файл:

hello

на этот раз Вы должны получить сообщение

Hi, there!

свидетельствующее, что команда сх сделала файл hello выполняемым.

Осталось установить команду сх в Ваш личный каталог bin

mv сх /usr/ < имя пользователя > /bin

и удалить ненужный файл:

rm hello

Заметьте, что сначала Вы воспользовались интерпретатором, задав sh сх сх и тем самым сделав файл сх выполняемым (командой). Первоначальное прямое обращение сх сх не дало бы такого результата, т.к. файл сх не был бы выполнен - отсутствовало право на его выполнение. А обращение к интерпретатору sh позволило выполнить командную строку файла сх, которая определила право на выполнение файла сх, т.к. он был задан в качестве параметра.

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

chmod +х $1 $2 $3 $4 $5 $6 $7 $8 $9

(Это годится только для девяти аргументов, так как конструкция $10 распознается как первый аргумент, за которым следует 0!) Если пользователь такого командного файла задаст меньше девяти аргументов, то недостающие окажутся пустыми строками. Это приведет к тому, что только настоящие аргументы будут переданы chmod. Такое решение, конечно, приемлемо, но не вполне корректно и не подходит для случая с числом аргументов более девяти.

Однако интерпретатор предоставляет возможность задания "всех аргументов" с помощью символа $*. Поэтому правильно определить сх так:

chmod +х $*

Такая команда является эффективной при любом числе аргументов.

Используя $*, Вы можете создавать полезные командные файлы. Например, такие как файл lc, осуществляющий подсчет строк в файлах с помощью командной строки wc -l $*. Создайте этот скрипт самостоятельно.

Аргументами командного файла не обязательно должны быть имена файлов. Создайте с помощью редактора vi файл /usr/ < имя пользователя > / phone-book, содержащий строки следующего вида:

My-Office 212-976-3838

My-college 212-246-4200

Petrov Vanya 212-976-3636

Simonova Klara 212-976-4141

Для поиска в нем можно воспользоваться командой grep. Составьте справочную программу 09 для поиска телефонных номеров в указанном файле:

echo 'grep $* /usr/ < имя пользователя > /phone-book' >09

этой командой Вы создали файл 09, содержащий команду поиска заданного шаблона в файле /usr/ < имя пользователя > /phone-book.

cx 09

с помощью скрипта cx Вы сделали файл 09 выполняемым.

Теперь необходимо проверить, как работает новый командный файл 09. Введите команду

09 му

Если Вы все сделали правильно, то на экране должны появится строки

My-Office 212-976-3838

My-college 212-246-4200

доказывающие, что Вы добились результата. Но не спешите радоваться, попробуйте и такой вариант

09 'Petrov Vanya'

Что-то не так, вместо номера телефона Петрова Вани Вы получили сообщение от команды grep:

grep: can't open Vanya

Дело в том, что команда 09 воспринимает Petrov Vanya как единый аргумент (он ведь заключен в апострофы), но для команды grep это уже два аргумента, и второй она воспринимает как имя файла. Обойти эту проблему можно, использовав кавычки. Несмотря на то, что большинство символов, заключенных в кавычки используются интерпретатором непосредственно, он все же "заглядывает" внутрь кавычек в поиске комбинаций с $, \, `...`. Поэтому если изменить команду 09 следующим образом:

grep "$*" /usr/ < имя пользователя > /phone-book

то $* заменяется аргументами, но команде grep передается как один аргумент, даже при наличии пробелов.

Попробуйте снова:

09 Petrov Vanya

Не забудьте поместить новый скрипт в Ваш каталог bin.

Еще одно замечание. Аргумент $0 - это имя выполняемой программы; например, в случае сх $0 есть "сх". Применение $0 находит в реализации программ 2, 3, 4, ... , которые печатают свой выходной поток в несколько столбцов.

Команды 2, 3, 4 ... и т.д. создаются с помощью команды pr и метасимволов $0 и $1. А также команды ln.

Достаточно создать один файл, например, 2:

echo 'pr -$0 -t -ln $*' >2

Флаг -tубирает заголовки в начале страницы, а флаг -ln устанавливает размер страницы равным n строк. Имя программы становится числом столбцов, т. е. аргументом команды pr. Не забудьте сделать файл выполняемым.

Остальные программы будут связями:

ln 2 3; ln 2 4;ln 2 5;ln 2 6;

Проверьте результаты работы новых команд:

who | 2

ls | 3

Результат выполнения программы в качестве аргумента.

Результат выполнения любой программы можно использовать в командной строке, заключив ее вызов в символы слабого ударения `...`:

echo Today's date & time: `date`.

данная командная строка выдает дату с замечанием, что это текущие дата и время.

Небольшое изменение показывает, что `...` интерпретируется и внутри кавычек "...":

echo " Today's

> date & time: `date`."

выдается та же информация в две строки.

Переменные shell.

shell позволяет определять переменные, точнее присваивать им значения, т.к. тип переменных один - строковые. Такие строки, как $1, $2 и т. д. являются позиционными параметрами-переменными, хранящими аргументы командного файла. Цифра показывает положение параметра в командной строке. Переменные, задающие позиционные параметры, не могут быть изменены.

Ранее Вы встречались с другой переменной - PATH, имеющей специальное значение. Если забыть о позиционных параметрах, переменные shell можно создавать, выбирать и изменять.

He все переменные имеют специальное значение для интерпретатора. Вы можете создавать новые переменные, присваивая им значения. По традиции переменные, имеющие специальное значение, обозначаются прописными буквами, а обычные переменные - строчными. Типичным примером использования переменных является хранение в них длинных строк, таких, как полные имена файлов.

Чтобы присвоить значение переменной, нужно использовать оператор "=", а для получения ее значения следует добавить перед именем переменной символ "$". Создайте, например, переменную foo, задав

foo="hello there"

Переменной foo присвоено значение "hello there". Теперь Вы можете обратиться к этой переменной, добавив перед ее именем символ "$". Команда

echo $foo

дает тот же самый результат, что и

echo "hello there"

Эти переменные являются внутренними для shell. Что означает - лишь shell имеет доступ к этим переменным. Это может быть полезно для сценариев. Команда

set

позволяет Вам увидеть перечень всех определенных переменных shell. (Для просмотра одной или двух переменных более подходит команда echo).

shell позволяет экспортировать переменные в среду. Среда - это множество переменных, к которым могут иметь доступ все выполняемые команды. Определив однажды переменную внутри shell, командой export Вы можете передать ее среде. Среда позволяет конфигурировать некоторые команды за счет установки переменных, о которых знают команды.

Вот небольшой пример.

Переменная среды PAGER используется командой man. Она указывает команду, которая используется в свою очередь командой man для просмотра Справочного руководства на экране. Если Вы установите в качестве значения PAGER имя другой команды, то эта команда будет обеспечивать просмотр вместо more (которая применялась по умолчанию).

Присвойте PAGER значение "cat":

PAGER=cat

Теперь экспортируйте PAGER в среду:

export PAGER

Попробуйте команду:

man ls

Выдача на экран руководства произойдет не поэкранно, как это делала команда more, а разом.

Теперь, если присвоить PAGER значение "more", то для выдачи на экран будет использоваться команда more:

PAGER=more

Обратите внимание на то, что не надо заново использовать команду export после изменения значения PAGER. Необходимо только раз экспортировать переменную; любые изменения, которые будут происходить после этого, будут отражаться в среде.

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

echo $HOME

Другая интересная переменная среды - PS1, которая определяет системное приглашение shell. Например:

PS1="Your command, please: "

Теперь вместо символа $, на экране будет появляться просьба ввести команду:

"Your command, please: "

Для переустановки приглашения обратно в нормальное состояние, выполните следующее:

PS1=$