Библиотека сайта rus-linux.net
Оболочки
Автор: Денис Колисниченко, dhsilabs@mail.ru
Опубликовано: 31.07.2002
Оригинал: http://www.softterra.ru/freeos/19209/
Программы-оболочки.
Интерпретатор
bash
Командный язык
bash
- Переменные.
- Массивы.
- Специальные переменные.
- Арифметические выражения
- Подстановка переменных. Подстановка значений.
- Управляющие структуры.
- Циклы.
- Подоболочки
Программы-оболочки.
В той статье мы поговорим о неотъемлемой части
пользовательского интерфейса Linux - о программах-оболочках. Именно
программа-оболочка запускается после регистрации пользователя в системе.
Программы-оболочки часто называют командными интерпретаторами, потому что они
обрабатывают (интерпретируют) команды, введенные пользователем. Во времена DOS
этим занимался файл C:\command.com.
В файле /etc/passwd для каждого
пользователя указывается, какую оболочку он будет использовать.
root:x:0:0:root:/root:/bin/bash den:x:501:501:Denis:/home/den:/bin/bash
Из листинга видно, что оба пользователя
используют оболочку /bin/bash. Оболочка, как правило, указывается в последнем
поле файла passwd.
Список всех установленных в системе программ-оболочек
содержится в файле /etc/shells. У меня он выглядит так:
Листинг 1.
/bin/sh /bin/bash /bin/ash /bin/bsh /bin/tcsh /bin/csh /bin/zsh
На любой Unix-системе, даже на самой старой, вы
можете увидеть, по крайней мере, два интерпретатора из этого списка: sh, csh.
Названия, как вы догадались, исходят от слова shell - оболочка. Csh - это
оболочка, использующая командный язык, напоминающий язык программирования C. В
ОС Linux по умолчанию используется оболочка bash (Bourne Again Shell). Bash
является более <продвинутой> версией обыкновенной оболочки sh.
Все оболочки
выполняют одну и туже функцию - интерпретируют команды пользователя. Например,
когда вы вводите команду
$ program -s /etc/passwd
Интерпретатор запустит программу program и
передаст ей два (точнее три)параметра: первый - это -s, второй - это
/etc/passwd. А что делать с этими параметрами разберется сама программа. Я
что-то говорит о третьем параметре? Существует еще один так называемый нулевой
параметр. Этот параметр содержит полное имя файла программы. Например, если наша
программа находится в каталоге /bin, то нулевой параметр будет содержать
значение /bin/program.
Обратите внимание на знак доллара возле команды. Это
признак того, что сейчас мы работаем как обыкновенный пользователь. Если мы
зарегистрируемся как пользователь root (суперпользователь), то знак доллара
измениться на решетку - #.
Отличием каждой программы-оболочки является ее
командный язык. Вот поэтому одни пользователи предпочитают использовать bash, а
другие - tcsh. Командные языки некоторых оболочек очень похожи, например, sh и
bash, csh и tsch.
Командный язык используется для создания сценариев.
Сценарий - это последовательность команд, которую должен выполнить интерпретатор
команд. Пример простейшего сценария (командный язык bash):
Листинг 2.
#!/bin/bash echo -n "Enter your name" read name echo "Hello, $name"
Для определенности скажем, что мы сохранили
этот сценарий под именем script1. Чтобы мы могли выполнить этот сценарий нужно
сделать этот файл исполнимым (например, с помощью команды chmod 550 ./script1) и
ввести команду (я предполагаю, что вы создали этот файл в текущем каталоге):
./script1
При запуске сценария программа-оболочка определяет, какую программу нужно запустить для обработки этого сценария. После этого интерпретатор запускает нужную программу и передает ей имя файла сценария в качестве параметра. В нашем случае интерпретатор выполнит команду (первая строка листинга 2):
/bin/bash ./script1
При этом не имеет значения, какой интерпретатор сейчас активен: будет запущена программа, указанная в первой строке сценария. Вы можете указать также и опции программы-оболочки:
#!/usr/bin/myshell -option
При запуске сценария, в первой строке которого
стоит такая команда, интерпретатор выполнит команду:
/usr/bin/myshwll
-option <имя_файла_сценария>
Обратите внимание на первую строку сценария
script1
#!/bin/bash
Это указание программы для обработки этого сценария.
Если же вы напишете
# !/bin/bash
то это будет уже обыкновенным
комментарием и система не сможет выполнить ваш сценарий, поскольку не будет
знать, какую программу-оболочку нужно использовать. В лучшем случае, если сейчас
активным является интерпретатор, на языке которого написан сценарий, файл
все-таки будет выполнен, а в другом случае вы получите сообщение об ошибке.
Например, если вы написали сценарий на bash, не указав (или неправильно указав)
интерпретатор, и пытаетесь выполнить его при запущенном интерпретаторе csh, то
получите сообщение о синтаксической ошибке.
Интерпретатор bash
В этой статье я рассмотрю оболочку bash, которая стандартна для большинства систем. Однако сам командный язык подробно разобран не будет из-за его объемности. Итак, начнем по порядку с регистрации пользователя. Как я уже отмечал, после успешной аутентификации пользователя, запускается программа-оболочка (в нашем случае это /bin/bash). При запуске оболочки выполняются некоторые действия. Эти действия определены в файле ~/.bash_profile (см. листинг 3).
Листинг 3.
# .bash_profile # Get the aliases and functions if [ -f ~/.bashrc ]; then ~/.bashrc fi # User specific environment and startup programs PATH=$PATH:$HOME/bin BASH_ENV=$HOME/.bashrc USERNAME="user" HISTIGNORE=" [ ]*:&:bg:fg" export USERNAME BASH_ENV PATH HISTIGNORE clear
Файл .bash_profile представляет собой обыкновенный сценарий. Теперь разберемся, какие действия выполняет этот сценарий. В этом файле определяются переменные окружения и программы, которые должны запускаться автоматически. В листинге 3 сначала проверяется существование файла .bashrc и, если он существует, интерпретатор выполняет его. Файл .bashrc рассмотрим немного позже. Затем устанавливаются переменные окружения: PATH, BASH_ENV, USERNAME, HISTIGNORE. Первая задает путь для поиска программ, вторая определяет среду интерпретатора (файл .bashrc), третья устанавливает имя пользователя, а последняя относится к истории команд, введенных пользователем. Затем переменные экспортируются. Дело в том, что переменные локальны в рамках сценария. При экспорте переменных их значение будет доступно порожденным процессам. Например, создайте такие два сценария (см. листинги 4 и 5).
Листинг 4.
#!/bin/bash MYVAR="My var" export MYVAR ./listing5
Листинг 5
#!/bin/bash echo "$MYVAR"
Запустите сценарий ./listing4. Он экспортирует
переменную MYVAR и запустит сценарий listing5, которые выведет значение
переменной MYVAR (<My var>) на экран. Теперь закомментируйте строку:
export
MYVAR
в сценарии listing4 и запустите его снова. На экране значение
переменной MYVAR не будет отображено.
Теперь вернемся к файлу .bashrc, а
потом перейдем к командному языку оболочки bash.
Листинг 6
# .bashrc # User specific aliases and functions alias rm='rm -i' alias mv='mv -i' alias cp='cp -i' alias s='cd ..' alias d='ls' alias p='cd -' # Need for a xterm & co if we don't make a -ls [ -n $DISPLAY ] && { [ -f /etc/profile.d/color_ls.sh ] && source /etc/profile.d/color_ls.sh export XAUTHORITY=$HOME/.Xauthority } # Read first /etc/inputrc if the variable is not defined, and after the /etc/inputrc # include the ~/.inputrc [ -z $INPUTRC ] && export INPUTRC=/etc/inputrc # Source global definitions if [ -f /etc/bashrc ]; then . /etc/bashrc fi
Здесь задаются определенные установки. В
основном данные установки необходимы для удобства пользователя. Например,
определяются псевдонимы команд (alias).
Оболочка bash использует еще один
командный файл - .bash_logout. В этом файле указываются действия, которые нужно
выполнить при выходе из интерпретатора, то есть выхода из системы.
Командный язык bash. Переменные.
Обязательным атрибутом переменной в любом языке
программирования является тип значения переменной. В командном языке bash все
переменные текстовые. Например, если вы присваиваете переменной значение A=23,
то значением переменной будет строка из двух сиволов - <23>.
Имя переменной
должно начинаться с буквы и может состоять из латинских букв, цифр, знака
подчеркивания.
Оператор присваивания в bash выглядит так:
<имя
переменной>=значение.
Например,
NAME=Ivan
Если нужно присвоить значение, содержащее пробелы, нужно использовать кавычки:
NAME="Ivan Ivanov"
Обращение к значению переменной выполняется с помощью знака доллара перед именем переменной:
echo "NAME"
echo "$NAME"
Первая команда выведет на экран слово NAME, а вторая - значение переменной NAME (Ivan Ivanov). Если значение переменной может содержать пробелы, имя переменной нужно заключить в кавычки. Например,
NAME="Ivan Ivanov"
echo $NAME
echo
"$NAME"
Первая команда echo выведет на экран слово
Ivan, а вторая - Ivan Ivanov.
Интерпретатор bash использует такие
метасимволы, имеющее для него особое значение:
* ? ; & ( )
| ^ < > <возврат_каретки> <табуляция> <пробел&qt;
Для того, чтобы использовать эти символы как они есть, нужно их цитировать с
помощью символа \. Например, символ перевода строки можно цитировать так \n,
символ табуляции - \t, символ вопроса - \?
Особое значение при присваивании
переменным значений имеют кавычки. Все символы, заключенные в одинарные кавычки
' ' представляют самих себя. Между двойными кавычками " " выполняются команды и
подстановки значений.
Символы "\", ",", " ' ", " $ " могут цитироваться с
помощью обратной наклонной черты: \\, \$, \'
Массивы.
Оболочка bash поддерживает одномерные массивы с
неограниченным числом элементов. В других интерпретаторах существуют
определенные ограничение на массивы, например, в ksh максимальное число
элементов массива ограничено 1024-мя элементами.
Присвоить значение элементу
массива можно с помощью такой конструкции:
Имя_массива[индекс]=значение
Например
Array[1]=23
Array[3]=54
Array[0]=77
Нумерация элементов начинается с ноля. Тип
элементов массива, как и тип переменных, текстовый.
Присвоить значение
элементам массива можно также с помощью инструкции set. Например, выражение
set -A array 3 56 77 12
Аналогично выражениям
array[0]=3
array[1]=56
array[2]=77
array[3]=12
Обратиться ко всем элементам массива сразу
можно так:
${array[@]}, где array - имя массива.
Например, echo
${array[@]}
Специальные переменные.
Каждому процессу доступны переменные оболочки, приведенные в таблице 1.
Таблица 1
Специальные переменные
Переменная | Значение |
HOME | Домашний каталог |
Имя файла, в который поступает электронная почта | |
LOGNAME | Имя пользователя, которое использовалось для входа в систему |
PATH | Путь вызова |
SHELL | Имя интерпретатора команд |
PWD | Текущий каталог |
UID | Идентификатор пользователя, запустившего сценарий |
RANDOM | Случайное число в диапазоне от 0 до 32767 |
SECONDS | Число секунд, прошедшее с момента запуска оболочки |
Кроме этих переменных устанавливаются и другие
переменные, назначение которых вы можете узнать в документации по bash.
В
таблице 2 представлены переменные, которые используются для обозначения
параметров командной строки.
Таблица 2.
Переменная | Значение |
$0 | Имя выполняемой команды. Для сценария - путь, указанный при его вызове. |
$1 | Первый параметр, указанный при вызове сценария. Аналогично, $2 - второй, $n - n-ый параметр. |
$# | Число параметров, которые были указаны при вызове сценария. |
$* | Все параметры, заключенные в кавычки: "$1 $2 ..." |
$? | Код завершения последней команды |
$$ | Номер текущего процесса (PID) |
Арифметические выражения
Подстановка арифметических выражений осуществляется с помощью конструкции
$(( выражение ))
Например,
N = $(( (10+5)/2 ))
echo $N
На экране вы увидите 3, а не 3,5, потому что
интерпретатор bash использует целочисленные вычисления.
Количество часов,
прошедшее с момента запуски оболочки можно вычислить так:
hrs = $((
$SECONDS/3600 ))
Подстановка переменных. Подстановка значений.
Интерпретатор bash предоставляет нам довольно гибкий механизм подстановки переменных. При этом переменная будет использоваться не всегда, а в зависимости от определенных обстоятельств. (см. таблицу 3).
Таблица 3.
${переменная:=значение} | Значение присваивается переменной, если она не определена или является пустой строкой. |
${переменная:?сообщение} | Если переменная не определена или является пустой строкой, выводится сообщение |
${переменная:+значение} | Если переменная инициализирована (определена), вместо нее используется указанное в конструкции значение. (*) |
${переменная} | Если переменная определена, подставляется ее значение. Скобки используются лишь для того, если после переменной стоит символ, который может <приклеиться> к имени переменной. |
${переменная:-значение} | Если переменная определена и не является пустой строкой, подставляется ее значение, иначе подставляется значение, указанное в конструкции. (*) |
(*) Реальное значение переменной не изменяется.
Пример: ${2 :? "Не хватает второго параметра"}
При подстановке команд нужно использовать обратные одинарные кавычки (они расположены под символом тильды на клавиатуре). Подставлять можно не только одну команду, а целые списки команд:
USERS='who | wd -l'
UP='date; uptime'
I='whoami'
В первом случае мы получим количество
пользователей работающих в системе, а во втором последовательно записанные
результаты выполнения команд date и uptime. В третьем случае мы просто получим
логин пользователя, под которым мы сейчас работаем в системе.
Подставлять
результаты выполнения можно не только в переменные, а и в другие команды,
например
grep 'id -un' /etc/passwd
Управляющие структуры.
К управляющим структурам относятся:
1.
Конструкция if-fi
2. Конструкция case-esac
Общий синтаксис конструкции if-fi
if список1 then
список2
elif список3 then
список4
else
список5
fi
Конструкция if-fi работает так же, как и в
других языках программирования.Если список1 (условие) истинный, выполняется
список2, иначе выполняется список3 и проверяется его истинность и т.д.
Допускается неограниченная вложенность операторов if.
Список - это список
команд. Разделителем команд служит символ <;>. Список обязательно должен
заканчиваться точкой с запятой. Пример списка: ls; dir; cat file;
При
программировании на bash есть один подводный камень, относящийся к логическим
выражениям. В других языках программирования выражение <истина> обозначается как
<true>, а <ложь> - как <false>. В языке C с выражением <ложь> сопоставляется
нулевое значение переменной, а за истину принимается любое ненулеое значение. В
bash все немного по-другому. За истину в конструкции if принимается 0, так как 0
- это код нормального завершения программы (команды). Правильнее конструкцию if
трактовать так: если код завершения списка команд, задающего условие в
конструкции if, равен 0, то будет выполнен список2. Код завершения последней
команды можно узнать с помощью переменной $?.
Например,
if [ $? -ne 0 ];
then echo "Ошибка. См. файл протокола"; fi;
В этом примере мы проверяем код
завершения последней команды. Если он не равен нулю (-ne), мы выводим сообщение
об ошибке. Кроме опции -ne можно использовать такие опции:
- -eq - равно
- -lt - меньше
- -gt - больше
- -le - меньше или равно
- -ge - больше или равно
- = - равно
- != - не равно
Символ "!" является символом логической
операции NOT (отрицание). Кроме этого символа, можно использовать опции команды
-o и -a, которые обозначают логические операции ИЛИ (OR) и И (AND).
Проверить существование файла можно опцией -e, а существование каталога - d.
Все эти опции являются параметрами программы test. Другими словами, вместо
квадратных скобок вы можете использовать команду test, поэтому следующие
выражения аналогичны
test -e /etc.passwd
[-e /etc/passwd]
Cинтаксис блока выбора (case - выбор):
case значение in
шаблон1) список1 ;;
...
шаблонN) списокN ;;
esac
Работает этот блок почти также, как в языке С.
Однако есть небольшая разница: если найдено совпадение с каким-нибудь шаблоном
(например, шаблонN-2) и выполнен соответствующий список команд списокN-2,
осуществляется выход из блока. В языке С для достижения этого эффекта нужно было
использовать оператор break, иначе выполнялись вы все списки после спискаN-2:
списокN-1, списокN.
Вместо дейтсвия по умочанию нужно использовать шаблон
*). Этот шаблон будет использоваться, когда не найдено совпадение ни с одним из
шаблонов. Например,
case $A in
1) echo "A=1";;
2) echo "A=2";;
*) echo "A<>1 and A<>2";;
esac
Циклы.
Интерпретатор bash поддерживает циклы for,
while, until, select, а интерпретатор sh только for и while.
В этой статье я
рассмотрю только первые два цикла - for и while.
Синтаксис цикла for:
for имя_переменной in список1
do
список2
done
Простой пример:
for i in 1 2 3 4 5; do echo $i; done
На экране вы увидите
1 2 3 4 5
Еще раз
напомню, что любой список в bash должен заканчивать точкой с запятой.
Построчно вывести содержимое файла file.txt мы можем с помощью такого цикла
for str in 'cat ./file.txt'
do
echo
"$str";
done
Цикл for закончит свою работу, когда будет обработан последний элемент списка, в данном случае, когда на экран будет выведена последняя строка файла file.txt
Синтаксис цикла while:
while список1
do
список2
done
Цикл while будет выполняться, пока условие, заданное в списке список1, будет истинным. Поэтому цикл while иногда называют циклом с истинным условием. Например,
a=1
while [$a -lt 10]
do
echo
$a
a = $(( $a + 1 ))
done
На экране вы увидите:
1 2 3 4 5 6 7 8 9
Когда переменная a примет значение 10, цикл завершит свою работу, так как
программа test вернет значение false (a уже не меньше, а равен 10).
Подоболочки
Рассмотрим два почти аналогичных сценария
#!/bin/bash # Сценарий 1 NUM="one"; (NUM="two"; echo $NUM;); echo $NUM #!/bin/bash # Сценарий 2 NUM="one"; {NUM="two"; echo $NUM;}; echo $NUM
Сценарий 1 выведет на экран следующую информацию:
two
one
А сценарий 2
two
two
Если список команд заключен в фигурные скобки, то он выполняется в текущей оболочке, а если в круглые - то в подоболочке. Механизм подоболочек, как вы уже успели догадаться, связан с областью действия переменных. Как и в любом другом языке программирования, в bash существуют два типа переменных: глобальный и локальные. Поскольку переменные в bash не описываются в начале программы, как в других языках, например, Pascal, внутри блока можно использовать как глобальные переменные (описанные в основном блоке сценария), так и локальные (описанные в этом блоке, при условии, что этот блок является подоболочкой).
В этой статье я попытался объять необъятное, поэтому совсем не удивительно, что некоторые возможности bash (функции, циклы until и select, протоколирование, обработка сигналов:) не рассмотрены, а некоторые рассмотрены не очень подробно (команда test). Возможно, эти возможности я рассмотрю в своих последующих статьях. А сейчас могу предложить вам список ссылок, посвященных bash, shell, а также Unix-системам вообще: http://dkws.narod.ru/linux/books_.html
с правилами использования материалов сайта <Софтерра> (http://www.softerra.ru/site/rules/)