Документация по ОС FreeBSD Пятница, 19.04.2024, 21:42
Приветствую Вас Гость | RSS
Меню сайта

Категории каталога
Shell [40]

Главная » Статьи » Программирование » Shell

Интерактивные интерфейсы пользователей
Командные интерпретаторы

Командный интерпретатор (по-другому - оболочка, shell) в операционных системах семейства UNIX предназначен для выполнения в основном следующих функций:

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

выполнение файлов, содержащих команды интерпретатора (командные файлы);

В системах UNIX (и во FreeBSD естественно) имеются несколько различных командных интерпретаторов. Наиболее популярные из них:

sh - Bourne shell.
csh - С-shell.
ksh - Korn-shell.
bash - Bourne Again shell.

Как правило, все shell находятся в каталоге /bin. Но это не обязательно. Вы помните, что когда мы рассматривали вопросы установки packages, то установили интерпретатор bash в каталог /usr/local/bin. Все установленные в системе оболочки перечислены в файле /etc/shells.

Наберите команду cat /etc/shells, и вы увидите примерно следующее:

/bin/sh
/bin/csh
/usr/local/bin/bash

Если строка в файле, в котором записаны команды интерпретатора, начинается на # , то эта строка - комментарий. Это не относится к самой первой строке файла. Она должна содержать запись, типа #!/bin/sh. Это указывает, что для выполнения команд будет вызван интерпретатор /bin/sh.

Далее рассмотрим возможности и языки командных интерпретаторов.

Базовые возможности командных интерпретаторов

Для определенности, в данной главе будем рассматривать интерпретатор bash. Если вам больше нравится работать и программировать в другой оболочке, можете в принципе пропустить изучение этой главы курса. Но замечу, что базовые возможности разных оболочек примерно одинаковые.

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

Все переменные в языке shell - текстовые. Их имена должны начинаться с буквы и могут состоять из латинских букв, цифр и знака подчеркивания (_). Bash поддерживает как простые переменные, так и массивы. Для установки переменной используется оператор =:

Для простых переменных

<имя>=<значение>

Для массивов

<имя>[индекс]=<значение>, либо
<имя>=(<значение1> <значение2> ... <значениеN>), либо
<имя>=([индекс1]=<значение1> [индекс2]=<значение2> ... [индексN]=<значениеN>)

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

Например:

# hour=14
# echo $hour

14

# hourth=24
# echo $hourth

24

# echo ${hour}th

14th

Двойные кавычки ( " ), одиночные кавычки ( ' ), обратные кавычки ( ` )
Кавычки могут использоваться для создания строк. Например:

"Hello, world!"
'Good bye'

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

` ~ ! # $ % ^ & * ( ) - + = | ; '" , . < > ?

Значения этих специальных символов в строках, заключенных в одиночные кавычки '<строка>' отменяются. В строках, заключенных в двойные кавычки "<строка>" также отменяются значения специальных символов, за исключением ! $ ` {. Обратная наклонная черта также отменяет действие специальных символов.

Не путайте одиночные и обратные кавычки. Пример:

# dat='date' (здесь стоят обратные кавычки)
# echo $dat

Mon Jun 05 14:17:20 2000

# dat='date' (здесь стоят одиночные кавычки)
# echo $dat

date

Конвейеры и списки

Несколько команд могут быть объединены с помощью символов канала |. В этом случае они образуют конвейер.

<команда1> | <команда2> | <команда3> ...

Символ канала | соединяет стандартный вывод команды <команда1> со стандартным вводом команды <команда2> и т.д.

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

Примеры:

# ps -ax | more
# ls -l | grep "profile"

Кроме конвейеров, команды могут объединяться в списки. Даже сами конвейеры могут быть объединены в списки. Это делается с помощью команд ; && ||.

Команда ; просто последовательно выполняет оду команду или конвейер за другой (другим):

# make depend ; make ; make install

# cat /etc/passwd | grep root ; echo "User root"

Для того, чтобы управлять выполнением следующей команды в списке в зависимости от состояния выхода предыдущей, используются команды && (логическое И) и || (логическое ИЛИ).

Примеры:

# mkdir mydir && cd mydir

В этом случае команда cd mydir будет выполнена только в том случае, если успешно (состояние выхода равно 0) завершится команда mkdir mydir.

# cat /home/bob/.profile || echo "Нет файла .profile"

В этом случае либо на экран будет выведено содержимое файла /home/bob/.profile, либо сообщение о том, что такого файла нет.

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

Команды и списки могут содержать операторы < и > - перенаправления стандартного ввода и стандартного вывода соответственно.

Например:

# ps -ax > /etc/proc

выводит текущее состояние процессов не на экран, а в файл /etc/proc. Если к этому моменту такого файла не было, то он будет создан. Если он существовал, то его старое содержимое будет уничтожено новой информацией.

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

# ps -ax >> /etc/proc

Кроме того, существует стандартный вывод ошибок. Он имеет дескриптор 2. Т.е. если мы не хотим получать сообщения об ошибках на стандартный вывод, то можно использовать перенаправление таким образом:

# cat /etc/proc 2>err.log (ошибки, если возникнут, будут выведены в файл err.log) либо
# cat /etc/proc 2>/dev/null (ошибки будут выведены "никуда", их посмотреть будет невозможно).

Ввод перенаправляется аналогичным образом. Например, команда

# mail billgates@msn.com < /home/mail.txt

отправит содержимое файла /home/mail.txt по адресу billgates@msn.com.

Оператор << означает, что ввод для данной команды находится "ЗДЕСЬ". Пример:

# mail billgates@msn.com << end
Hello, Bill!
end

По этой команде в тело письма войдет все, что встретится до указанного нами ограничителя ввода end.

Управление ходом выполнения. Циклы

Управлять ходом выполнения сценария на языке bash можно, используя кострукцию операторов if-fi. Оператор if имеет вид:

if <условие 1>; then
<список операторов 1>
elif <условие 2>; then
<список операторов 2>
else
<список операторов 3>
fi

Работает эта конструкция так:

Если выполнено <условие 1>, то выполняется <список операторов 1>.
Если невыполнено <условие 1>, но выполнено <условие 2>, то выполняется <список операторов 2>.
Если невыполнено <условие 1> и невыполнено <условие 2>, то выполняется <список операторов 3>.
В конструкции if-fi операторы elif и else являются необязательными.

В качестве условия проверки может быть использована любая команда (или список команд). Тогда условие будет считаться выполненным, если команда (список команд) завершилась с кодом 0 (т.е. выполнилась нормально). Но на практике чаще используют команду test для проверки какого-либо выражения. Команда test записывается так:

test <выражение> или же [<выражение>]. Ниже приводится список опций, используемых при выполнении команды test.

-d file Истинно, если файл file существует и является директорией.
-e file Истинно, если файл file существует.
-f file Истинно, если файл file существует и является обычным файлом.
-k file Истинно, если файл file существует и для него установлен sticky-бит.
-L file Истинно, если файл file существует и является символической ссылкой.
-r file Истинно, если файл file существует и его можно читать.
-s file Истинно, если файл file существует и имеет ненулевой размер.
-t file Истинно, если файл file открыт на терминале.
-w file Истинно, если файл file существует и в него можно записывать.
-x file Истинно, если файл file существует и является выполняемым.
-O file Истинно, если файл file существует и принадлежит текущему пользователю.
file1 -nt file2 Истинно, если файл file1 создан (изменен) позднее, чем файл file2.
file1 -ot file2 Истинно, если файл file1 создан (изменен) раньше, чем файл file2.
-z <строка> Истинно, если длина строки <строка> равна нулю.
-n string Истинно, если длина строки <строка> не равна нулю.
string1 = string2 Истинно, если строки равны.
string1 != string2 Истинно, если строки не равны.
! <выражение> Истинно, если выражение ложно.
<выражение1> -a <выражение2> Истинно, если оба выражения истинны.
<выражение1> -o <выражение2> Истинно, если хотя бы одно из выражений истинно.
<число1> -eq <число2> Истинно, если число <число1> равно числу <число2>.
<число1> -ne <число2> Истинно, если число <число1> не равно числу <число2>.
<число1> -lt <число2> Истинно, если число <число1> меньше числа <число2>.
<число1> -le <число2> Истинно, если число <число1> меньше или равно числа <число2>.
<число1> -gt <число2> Истинно, если число <число1> больше числа <число2>.
<число1> -ge <число2> Истинно, если число <число1> больше или равно числа <число2>. Числами <число1> и <число2> могут быть положительные и отрицательные целые числа.

Пример:

if [ -x /usr/games/pool ] ; then
/usr/games/pool
else
echo "не могу запустить файл"
fi

Этот же пример можно записать по-другому:

[ -x /usr/games/pool ] && /usr/games/pool || echo "не могу запустить файл"

Циклы реализуются с помощью конструкций for, while.

Цикл for записывается так:

for <переменная> in <список>
do
<команды>
done

Пример 1:

for i in 1 2 3
do
echo $i
done

Пример 2:

for file in /etc/p*
do
echo $file
done

Этот цикл эквивалентен команде ls /etc/p*.

Цикл while имеет вид:

while <условие>
do
<команды>
done

Команды в теле цикла выполняются до тех пор, пока остается истинным <условие>.

Пример:

i=1
while [ $i -lt 5 ]
do
echo $i
i = $(($i+1)) 
# можно было бы написать i=`expr $i + 1`
done

Другим вариантом цикла while является until.

until <условие>
do
<команды>
done

В этом случае команды в теле цикла выполняются до тех пор, пока <условие> остается ЛОЖНЫМ.

i=1
until ! [ $i -lt 5 ]
do
echo $i
i='expr $i + 1'
done

Заметим, что по команде break можно выйти из тела цикла. Это справедливо и для цикла for и для while (until). Пример:

i=1
while [ $i -gt 0 ]
do
echo $i
i=`expr $i + 1`
if [ $i -eq 10 ] ; then
break
fi
done

Передача аргументов. Команда shift.

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

# /usr/games/pool file1.txt user1

Для того, чтобы можно было работать с переданными аргументами, существует девять переменных - $1, $2, ... , $9. Они позиционно соответствуют переданным аргументам. Т.е. в нашем примере $1 содержит строку "file.txt", а $2 содержит строку "user1". Кроме того, в переменной $# содержится количество переданных аргументов. В нашем случае -2.

Но что делать, если нужно передать, скажет, 15 аргументов ? Как получить доступ к аргументу с номером больше 9 ?

Для этой цели существует команда shift, которая просто осуществляет сдвиг аргументов на одну позицию "влево". Т.е. $1 получает значение $2, $2 - $3 и т.д. При этом значение, которое было в $1 до сдвига - теряется. При этом сдвиге так же уменьшается на 1 значение $#.

Рассмотрим это на примере. Создайте такой файл

#!/usr/local/bin/bash
i=1
while [ $# -eq 0 ]
do
echo "Аргумент $i - $1"
shift
i=`expr $i + 1`
done
Назовите его, например, my_shift.

Запустите его так:

# my_shift p1 p2 p3 p4

На экране вы увидете:

Аргумент 1 - p1
Аргумент 2 - p2
Аргумент 3 - p3
Аргумент 4 - p
Упражнения

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

2. Напишите скрипт, который бы принимал в качестве параметров имена этих файлов и добавлял их содержимое в файл, который передан первым в командной строке.

3. Запустите скрипт. Затем откройте файл-приемник, и проверьте, все ли правильно работает?

Ответ (пример скрипта):

#!/usr/local/bin/bash
if [ $# -gt 1 ] ; then
file=$1
i=$#
shift
while [ $# -eq 0 ]
do
cat $1 >> $file
shift
done
echo "Всего к файлу $file добавлено `expr $i - 1' файлов"
else
echo "Недостаточно аргументов"
fi
Категория: Shell | Добавил: oleg (08.12.2007)
Просмотров: 1558 | Рейтинг: 0.0/0 |
Всего комментариев: 0
Добавлять комментарии могут только зарегистрированные пользователи.
[ Регистрация | Вход ]
Форма входа

Beastie

Друзья сайта

Статистика

Онлайн всего: 1
Гостей: 1
Пользователей: 0
links

Copyright MyCorp © 2024