C одержани е


РАЗДЕЛ 3. ПРОСТЕЙШИЕ СРЕДСТВА SHELL



страница3/6
Дата01.12.2017
Размер1.09 Mb.
ТипКонтрольные вопросы
1   2   3   4   5   6
РАЗДЕЛ 3. ПРОСТЕЙШИЕ СРЕДСТВА SHELL
3.1. Пользовательская среда UNIX

Командный язык shell (в переводе - раковина, скорлупа) фактически есть язык программирования, на котором пользователь осуществляет управление компьютером. Shell не является необходимым и единственным командным языком (хотя он стандартизован в рамках POSIX [POSIX 1003.2] – стандарта мобильных систем). Немалой популярностью пользуются языки сshell, kshell и др. Кроме того, каждый пользователь может создать свой командный язык, может одновременно работать на одном экземпляре операционной системы с разными командными языками.

Базовой пользовательской средой UNIX является окно алфавитно-цифрового терминала. Однако сегодня, в условиях конкуренции на рынке ОС для ПК, характер работы в UNIX существенно отличается от того, каким он был, скажем, пятнадцать лет назад. Графический многооконный интерфейс, системы меню, техника drag-and-drop, — все это, казалось бы, стирает различия в работе с OC UNIX и, например, с OC Windows.

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



3.2. Командный интерпретатор shell

Интерпретатор (shell) представляет собой интерфейс командной строки. По своей функциональности он похож на интерпретатор COMMAND.COM системы MS DOS. Одной из задач интерпретатора является обеспечение безопасного и структурированного доступа к ядру UNIX-подобных операционных систем, т.е. фактически это программный уровень, который предоставляет среду для ввода команд, обеспечивая тем самым взаимодействие между пользователем и ядром операционной системы. Кроме того, встроенный в интерпретатор мощный язык программирования используется для решения различных задач: от автоматизации повторяющихся команд до написания сложных интерактивных программ обработки данных, получения информации из небольших баз данных.

В среде UNIX существует много командных интерпретаторов, среди которых можно выделить такие как sh, tcsh, ksh, csh, bash, в Linux по умолчанию используется bash.

В табл. 3.1. приведены встроенные команды интерпретатора shell.



Таблица 3.1. Встроенные команды интерпретатора shell

команда

Значение

:

нуль, всегда возвращает истинное значение

.

считывание файлов из текущего интерпретатора shell

break

применяется в конструкциях for, while, until, case

cd

изменяет текущий каталог

continue

продолжает цикл, начиная следующую итерацию

echo

записывает вывод в стандартный поток вывода

eval

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

exit

выход из интерпретатора shell

export

экспортирует переменные, они становятся доступны для текуще­го интерпретатора shell

pwd

отображает текущий каталог

read

просматривает строку текста из стандартного потока

readonly

превращает данную переменную в переменную "только для чтения"

return

выход из функции с отображением кода возврата

set

управляет отображением различных параметров для стандартного потока вводных данных

shift

смещает влево командную строку аргументов

Test

оценивает условное выражение

times

отображает имя пользователя и системные промежутки времени для процессов, которые выполняются с помощью интерпретатора shell

Trap

при получении сигнала выполняет определенную команду

Type

интерпретирует, каким образом интерпретатор shell применяет имя в качестве команды

Ulimit

отображает или устанавливает ресурсы интерпретатора shell

umask

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

Unset

удаляет из памяти интерпретатора shell переменную или функцию

Wait

ожидает окончания дочернего процесса и сообщает о его завершении

Сам интерпретатор shell автоматически присваивает значения следующим переменным (параметрам):

? - значение, возвращенное последней командой;

$ - номер процесса;

! - номер фонового процесса;

# - число позиционных параметров, передаваемых в shell;

* - перечень параметров, как одна строка;

@ - перечень параметров, как совокупность слов;

- флаги, передаваемые в shell.

При обращении к этим переменным, т.е. при использовании в командном файле, следует впереди ставить "$".

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



3.3. Приемы экранирования

Рассмотрим приемы экранирования, используемые в shell. В качестве средств экранирования используются двойные кавычки (" "), одинарные кавычки (' ') и бэк-слэш (\).



Экранирующий символ (\), используемый совместно с командами echo и sed, сообщает интерпретатору, что следующий за ним символ должен восприниматься как специальный символ:

\n - перевод строки (новая строка);

\r - перевод каретки;

\t - табуляция;

\v - вертикальная табуляция;

\b - забой (backspace);

\a - "звонок" (сигнал);

\0xx - ASCII-символ с кодом 0xx в восьмеричном виде.

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



cat file | grep -h \

result | sort | cat -b > filerez

аналогична записи:



cat file | grep -h result | sort | cat -b > filerez
Ниже приведены примеры использования экранирующих символов (\):

- вывод последовательности символов:



echo "\s\s\s"\

- вывод вертикальной табуляции:



echo -e "\s\s\s"

- вывод символа " (кавычки с восьмеричным кодом ASCII 42):



echo -e "\042"

Конструкция $'\X' делает использование ключа -e необязательным;



- запись ASCII-символов в переменную, например, символа “ :

quote=$'\042'

3.4. Организация циклов и ветвлений

3.4.1. Условный оператор "if"

В общем случае оператор "if" имеет структуру:



if условие

then список

[elif условие

then список]

else список]

fi

Служебное слово "elif" - сокращенный вариант от "else if", может быть использован наряду с полной записью, т.е. допускается вложение произвольного числа операторов "if" (как и других операторов). Если выполнено условие, то выполняется "список", иначе он пропускается. Структура обязательно завершается служебным словом "fi". Число "fi" всегда должно соответствовать числу "if".



3.4.2. Команда test

Команда test проверяет выполнение некоторого условия. С использованием этой (встроенной) команды формируются операторы выбора и цикла языка shell. Имеется два возможных формата команды:



test условие

или


[ условие ]

Интерпретатор shell будет распознавать эту команду по открывающей скобке "[". Между скобками и содержащимся в них условием обязательно должны быть пробелы. Пробелы должны быть и между значениями и символом сравнения или операции. В shell используются условия различных "типов":

1) условия сравнения целых чисел:

x eq y - "x" равно "y",

x ne y - "x" не равно "y",

x gt y - "x" больше "y",

x ge y - "x" больше или равно "y",

x lt y - "x" меньше "y",

x le y - "x" меньше или равно "y".

2) сложные условия, реализуемые с помощью типовых логических операций:

! (not) инвертирует значение кода завершения;

-o (or) соответствует логическому "ИЛИ";

-a (and) соответствует логическому "И".

3) условия проверки файлов:

-f file - файл "file" является обычным файлом;

-d file - файл "file" - каталог;

-с file - файл "file" - специальный файл;

-r file - имеется разрешение на чтение файла "file";

-w file - имеется разрешение на запись в файл "file";

-s file - файл "file" не пустой.

4) условия проверки строк:

str1 = str2 - строки "str1" и "str2" совпадают;

str1 != str2 - строки "str1" и "str2" не совпадают;

-n str1 - строка "str1" существует (непустая);

-z str1 - строка "str1" не существует (пустая).

3.4.3. Оператор цикла с перечислением – for

Оператор цикла "for" имеет структуру:

for имя in список-значений

do

список команд

done

где for - служебное слово, определяющее тип цикла, do и done - служебные слова, выделяющие тело цикла. Фрагмент in список-значений может отсутствовать.

Рассмотрим пример:

for i in f1 f2 f3

do

proc-sort $i

done

В этом примере имя i играет роль параметра цикла. Это имя можно рассматривать как shell-переменную, которой последовательно присваиваются перечисленные значения (i=f1, i=f2, i=f3), и выполняется в цикле команда procsort.

Часто используется форма for i in *, означающая для всех файлов текущего каталога.

3.4.4. Оператор цикла с истинным условием - while

Структура оператора while предпочтительнее тогда, когда неизвестен заранее точный список значений параметров или этот список должен быть получен в результате вычислений в цикле. Оператор цикла while имеет структуру:

while

условие

do

список команд

done ,

где while - служебное слово, определяющее тип цикла с истинным условием. Список команд в теле цикла (между do и done) повторяется до тех пор, пока сохраняется истинность условия (т.е. код завершения последней команды в теле цикла равен 0) или цикл не будет прерван изнутри специальными командами (break, continue или exit). При первом входе в цикл условие должно выполняться.



3.4.5. Оператор цикла с ложным условием until

Отличие оператора цикла until от оператора while состоит в том, что условие цикла проверяется на ложность (на ненулевой код завершения последней команды тела цикла) после каждого (в том числе и первого) выполнения команд тела цикла. Программистов, знакомых с операторами until в других языках, может вначале сбивать такая семантика этого оператора.

Оператор цикла until имеет структуру:

until условие

do

список команд

done

где until - служебное слово, определяющее тип цикла с ложным условием. Список команд в теле цикла (между и done) повторяется до тех пор, пока сохраняется ложность условия или цикл не будет прерван изнутри специальными командами (break, continue или exit). При первом входе в цикл условие не должно выполняться.

Кроме рассмотренных операторов ветвления и циклов существует ряд других операторов, которые можно найти в приведенной в списке литературе.

3.5. Функции интерпретатора shell

Интерпретатор команд shell позволяет группировать наборы команд или конст­рукций, создавая повторно используемые блоки. Подобные блоки называются shell-функциями.

Функция состоит из двух частей:

Метка функции Тело функции

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

Формат, применяемый для определения функций, имеет следующий вид:

имя функции ( )

{

команда1



}

Можно также использовать ключевое слово function перед именем функции:

function имя_функции ( )

{

}

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

Функции могут быть размещены в том же самом файле, что и сценарии, либо в отдельном файле, содержащем функции. При этом функции не всегда включают множество конструкций или команд - может просто содержаться единственная кон­струкция echo, которая выполняется при вызове функции.

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



3.5.1. Объявление функций в сценарии

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



hello ()

(

echo "Hello there today's date is Mate*"

}

В этом примере функция называлась "hello", тело функции включало конст­рукцию echo, которая, в свою очередь, отображала текущую дату.



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

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



$ pg fund

#!/bin/sh

# funcl

hello ()

{

echo "Hello there today's date is ‘date

}

echo "now going to the function hello" hello

echo "back from the function"

При выполнении этого сценария получаются следующие результаты:



$ fund

now going to the function hello

Hello there today's date is Sun Jun 6 10:46:5?9 GMT 2000

back from the function

В предыдущем примере функция была объявлена в начале сценария. Для обра­щения к функции просто вводится ее имя, в данном случае "hello*. После завершения выполнения функции управление возвращается следующей кон­струкции, которая размещена после вызова функции. В приведенном примере речь идет о конструкции echo "back from the function".



3.5.3. Передача параметров функции

Порядок передачи параметров функции аналогичен передаче параметров обычному сценарию. При этом используются специальные переменные $1, $2, ... $9. При получении функцией переданных ей аргументов происходит замена аргументов, изначально переданных сценарию интерпретатора shell. В связи с этим желательно было бы повторно присвоить значения переменным, получаемым функцией. В любом случае это стоит сделать, так как при наличии ошибок в функциях их можно будет легко обнаружить, воспользовавшись именами лекальных переменных. Для вызы­вающих аргументов (переменных), находящихся внутри функции, имя каждой пере­менной начинается с символа подчеркивания, например: _FILENAME или _filename.



3.5.4. Возврат значения функции

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

1) завершение функции и последующая передача управления той части сценария, которая вызвала данную функцию;

2) использование ключевого слова return, в результате чего будет осуществлена передача управления конструкции, которая расположена за оператором вызова функции. При этом может также указываться необязательный числовой параметр. Этот параметр принимает значение 0 в случае отсутствия ошибок и значение 1 - при наличии ошибок. Действие этого параметра аналогично действию кода завершения последней команды.

При использовании ключевого слова return применяется следующий формат:

return - возвращает результат из функции, использует код завершения последней команды для проверки состояния;

return 0 - применяется при отсутствии ошибок;

return 1 - применяется при наличии ошибок.

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



check_it is_a_directory $FILENAME # вызов функции и проверка

if [ $? = 0 ] # применение кода завершения

# последней команды для тестирования

then

echo "All is OK"

else

echo " Something went wrong! "

fi

Лучшим методом является использование оператора if, с помощью которого осуществляется проверка возвращаемого значения (0 или 1). Встраивание вызова функции в структуру оператора if значительно улучшает читабельность програм­много кода. Например:



if check_it_is_a_directory $FILENAME;

then

echo "All is OK"

# действия

else

echo "Something went wrong!"

# действия

fi

Если функцию планируется использовать для отображения результатов некоторой проверки, для фиксации результата применяется подстановка. Формат, используемый для выполнения подстановки при вызове функции, следующий:



имя_переменной = ‘имя_функции‘

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



3.5.5. Файл функций

Файл функций содержит несколько регулярно используемых функций. В начале этого файла должна находиться конструкция #!/bin/sh. Файлу функций можно присвоить любое имя, затем загрузить этой файл в среду интерпрета­тора shell. Как только файл будет загружен интерпретатором shell, появляется возможность вызова функций из командной строки либо из сценария. Для просмотра всех определенных функций можно воспользоваться командой set. Поток вывода будет содержать все функции, которые были загружены интерпретатором shell.

Для изменения любой из ранее определенных функций используется команда unset, после чего функция будет выгружена из интерпретатора shell. После внесения изменений в файл функций необходимо выполнить его перезагрузку. В результате этого данную функцию будет невозможно вызвать из пользовательских сценариев или интер­претатора команд, хотя физического удаления функции при этом не происходит. Некоторые интерпре­таторы команд могут распознавать изменения, и в этом случае применение команды unset вовсе не обязательно. Однако все же в целях безопасности следует исполь­зовать данную команду при модификации функций интерпретатора shell.

3.5.6. Создание файла функций

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

Создаваемый файл функций, например functions.main, будет содержать следующий код:

$ pg functions.main

#!/bin/sh

# functions.main

# findit: интерфейс для базовой команды find

findit () (

# findit

if [ $# -It 1 ];

then

echo "usage :findit file"

return 1

fi

find / -name $1 -print

В данном примере создается файл функций functions.main, включающий одну функцию. Эта функция будет загружена интерпретатором команд, протестирована, изменена, а затем повторно загружена. Данный код лежит в основе интерфейса для базовой команды find. Если команде не передаются аргументы, то возвращается значение 1 (что свидетельствует о возникновении ошибки). Обратите внимание, что ошибочная конструкция фактически является отображенным именем функции (если же была использована команда $0, интерпретатор команд просто возвращает сообщение sh). Причина отображения по­добного сообщения заключается в том, что файл не является файлом сценария.



3.5.7. Подключение файла функций и проверка загруженных функций

Команда подключения файла функций имеет следующий формат:



. /путь/имя_файла

Например, $. functions.main. Если в результате выполнения этой команды возвращается сообщение «File not found» (файл не найден), можно воспользоваться следующей командой:



$ . / functions. main

В этом случае применяется нотация



<точка><пробел><косая черта><имя файла>.

Для проверки загруженности интерпретатором команд функции используется команда set, которая отображает все загруженные функции, доступные для сценария:



$ set

USER=stud

findit=()

[

if ( $# -It 1 ]; then

echo "usage :findit file"; return 1;

find / -name $1 -print

}


3.5.8. Вызов функций интерпретатора shell

Для вызова функции необходимо ввести ее имя (в данном случае findit) и указать аргумент, в роли которого может выступать имя файла, размещенного в системе:



$ findit groups

/usr/bin/groups /usr/local/backups/groups.bak
3.5.9. Удаление shell-функций

Для выполнения операции удаления shell-функции применяется команда unset. При вызове данной команды используется следующий формат:



unset имя_функции

Например:



$ unset findit

Если ввести команду set, функция findit не будет найдена.



3.5.10. Редактирование shell-функций

Если добавить в функцию functions.main цикл, используя оператор for, то сценарий сможет считывать более одного параметра из командной строки. Функция приобретет следующий вид:



$ pg functions.main

#!/bin/sh

findit()

{

# findit

#if [ $# -It 1 ]

then

echo "usage :findit file"

return 1

fi

for loop

do

find / -name $loop -print

done

}

Если интерпретатор shell корректно интерпретирует цикл for и воспринимает все требуемые параметры, на экране отобразится соответствующее сообщение:



$ set findit=()

{

if [ $# -It 1 ] then

echo "usage :'basename $0' file";

return 1;

fi;

for loop in "$@";

do

find / -name $loop -print;

done

}

Далее вызывается измененная функция findit. При этом поддерживаются два файла с целью осуществления поиска:



$ findit SPO.doc passwd

/usr/local/accounts/SPO.doc

/etc/passwd



3.6. Применение shell-сценариев

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

В сценариях используются переменные, условные, арифметические и циклические конструкции, которые можно отнести к системным командам. За счет этих возможностей сценарии создаются довольно быстро. Интер­претатор команд может применять в качестве вводных данных для одной команды информацию, полученную при выполнении другой команды. Чтобы shell-сценарий применялся в различных системах UNIX и Linux, в него нужно внести лишь небольшие изменения. Это связано с тем, что интерпретатор shell обладает высокой степенью универсальности. Определенные трудности возникают лишь вследствие ориентации системных команд на определенные системы.

Сценарий не относится к компилируемым программам, поскольку он интерпре­тируется построчно. Первой строкой сценария всегда должна быть строка вида:



#!/bin/sh

Таким образом, система получает указание, где следует искать интерпретатор Bourne shell. Каждый сценарий может содержать комментарии; если комментарии размеща­ются в сценарии, первым символом в строке комментария будет символ #. Встретив подобный символ, интерпретатор команд игнорирует строку комментария. Сценарий просматривается интерпретатором команд в направлении сверху вниз. Перед выполнением сценария требуется воспользоваться командой chmod, устанав­ливающей право доступа на выполнение. Для выполнения сценария достаточно указать имя файла сценария.

Приведенный ниже сценарий отменяет отображение сообщений var/adm/ путем усечения файла сообщений. В задачи этого сценария также входит удаление всех журнальных файлов в каталоге /usr/local/apps/log:

$ pg cleanup

#!/bin/sh

# имя: cleanup

# это общий сценарий/ выполняющий очистку echo "starting cleanup...wait"

rm /usr/local/apps/log/*.log

tail -40 /var/adm/messages /tmp/messages

rm /var/adm/messages

mv /tmp/messages /var/adm/messages

echo "finished cleanup"
Для выполнения сценария применим команду chmod:

$ chmod u+x cleanup

Для запуска сценария на выполнение необходимо ввести его название:



$ cleanup

При отображении сообщения об ошибке, например:



$ cleanup

sh: cleanup: command not found

воспользуйтесь командой:



$ ./cleanup

Если перед выполнением сценария нужно указать путь доступа к нему или же сценарий сообщает, что не может обнаружить команду, достаточно в значение переменной PATH из файла .profile добавить каталог bin. При вводе следующей информации сначала убедитесь, что вы находитесь в каталоге $НОМЕ/stud:



$ pwd

$ /home/stud/bin

Если последняя часть команды pwd включает название подкаталога /bin, его следует использовать при указании имени пути. Изменить файл .profile, добавив в него каталог $HOME/bin, можно, используя следующую команду:



PATH = §PATH:$HOME/bin

В случае, если подкаталог /bin отсутствует, необходимо создать его:



$ mkdir bin

Затем в файле .profile добавляется каталог bin в переменную PATH, и заново инициализируется файл .profile:



$ /.profile
Контрольные вопросы


  1. Что такое shell-процедура?

  2. Какого типа команды могут быть включены в тело процедуры?

  3. Чем отличается обработка процедуры при выполнении от обработки программы на языке высокого уровня?

  4. Поясните общую структуру скрипта.

  5. В каком виде хранятся переменные в программах командного интерпретатора?

  6. Что такое параметры? Для каких целей они используются?

  7. Какое число параметров может быть передано процедуре?

  8. Перечислите переменные (параметры), которым интерпретатор shell автоматически присваивает значения.

  9. Приведите примеры сложных синтаксических конструкций получения значений переменной.

  10. Перечислите внутренние переменные shell, используемые в скриптах.

  11. Как осуществляется ветвление вычислительного процесса процедуры?

  12. Какого типа циклы в процедурах могут быть построены средствами языка shell?

  13. Поясните процедуру создания файла функций.

  14. Как подключить файл функций?

  15. Поясните процедуру выполнения проверки загруженных функций.

  16. В каких случаях целесообразно использование shell-сценариев?





Поделитесь с Вашими друзьями:
1   2   3   4   5   6


База данных защищена авторским правом ©vossta.ru 2019
обратиться к администрации

    Главная страница