Введение в UNIX

Дегтярев Е.К.

Оглавление

7. Программирование в языке SHELL

7.1. Версии Shell

В начало страницы

  
   Shell - интерпретатор команд,  подаваемых с терминала или
из командного файла. Это обычная программа (т.е. не входит в
ядро операционной системы UNIX). Ее можно заменить на другую
или иметь несколько.

   Две наиболее известные версии:
   - Shell (версии 7 UNIX) или Bourne Shell (от фамилии  ав-
тора S.R.Bourne из фирмы Bell Labs) [5];
   - C-Shell (версии Berkley UNIX).
   
   Они похожи,  но есть и отличия: C-Shell мощнее в диалого-
вом режиме, а обычный Shell имеет более элегантные управляю-
щие структуры.

   Shell - язык программирования, так как имеет:
   - переменные;
   - управляющие структуры (типа if);
   - подпрограммы (в том числе командные файлы);
   - передачу параметров;
   - обработку прерываний.

7.2. Файл начала сеанса (login - файл)

В начало страницы

   Независимо от версии Shell при входе в систему UNIX  ищет
файл  начала сеанса с предопределенным именем,  чтобы выпол-
нить его как командный файл;

   - для UNIX версии 7 это: .profile;
   - для C-Shell это: .login и/или .cshrc.
   
   В этот файл обычно помещают команды:
   - установки характеристик терминала;
   - оповещения типа who, date;
   - установки каталогов поиска команд (обычно: /bin, /usr/bin);
   - смена подсказки с $ на другой символ и т.д.

7.3. Процедура языка Shell

В начало страницы

   Это командный файл. Два способа его вызова на выполнение:
   
   1. $ sh dothat (где dothat - некоторый командный файл);
   2. $ chmod  755  dothat  (сделать  его  выполнимым,  т.е.
      -rwxr-xr-x)
      $ dothat.
      
   Следует знать порядок поиска каталогов команд (по умолча-
нию):
   - текущий;
   - системный /bin;
   - системный /usr/bin.
   
   Следовательно, если имя вашего командного файла дублирует
имя  команды в системных каталогах,  последняя станет недос-
тупной (если только не набирать ее полного имени).

7.4. Переменные Shell

В начало страницы

   В языке  Shell  версии  7 определение переменной содержит
имя и значение: var = value.

   Доступ к переменной - по имени со знаком $ спереди:
   
   fruit = apple (определение);
   echo $fruit (доступ);
   apple (результат echo).

   Таким образом, переменная - это строка. Возможна конкате-
кация строк:

   $ fruit = apple
   $ fruit = pine$fruit
   $ echo $fruit
   pineapple
   $ fruite = apple
   $ wine = ${fruite}jack
   $ echo $wine
   applejack
   $
   
   Другие способы  установки  значения  переменной - ввод из
файла или вывод из команды (см. раздел 7.6), а также присва-
ивание  значений  переменной - параметру цикла for из списка
значений, заданного явно или по умолчанию (см. раздел 7.9).

   Переменная может быть:
   1) Частью полного имени файла:  $d/filename, где $d - пе-
ременная (например, d = /usr/bin).
   2) Частью команды:
   $ S = "sort + 2n + 1 - 2" (наличие пробелов требует кавы-
чек "")
   $ $S tennis/lpr
   $ $S basketball/lpr
   $ $S pingpong/lpr
   $
   Однако внутри  значения для команды не могут быть символы
|, >,  <,  & (обозначающие канал,  перенаправления и фоновый
режим).

7.5. Предопределенные переменные Shell

В начало страницы

   Некоторые из них можно только читать.  Наиболее употреби-
тельные:
   HOME - "домашний" каталог пользователя; служит аргументом
по умолчанию для cd;
   PATH - множество каталогов, в которых UNIX ищет команды;
   PS1  - первичная подсказка (строка) системы (для v.7 - $).
   Изменение PS1 (подсказки) обычно делается в login -  фай-
ле,  например:
    PS1 = ?
или PS1 = "? " (с пробелом, что удобнее).

   Изменение  PATH:
   $ echo $PATH         -  посмотреть;
   :/bin:/usr/bin       -  значение PATH;
   $ cd                 -  "домой";

   $ mkdir bin                  -  новый  каталог;
   $ echo $HOME                 -  посмотреть;
   /users/maryann               -  текущий   каталог;
   $ PATH  = :$HOME/bin:$PATH   -  изменение PATH;
   $ echo $PATH                 -  посмотреть;
   :/users/maryann/bin:/bin:/usr/bin - новое значение PATH.

7.6. Установка переменной Shell выводом из команды

В начало страницы

   Пример 1:
   $ now = `date` (где `` - обратные кавычки)
   $ echo $now
   Sun Feb 14  12:00:01 PST  1985
   $

   Пример 2: (получение значения переменной из файла):
   $ menu = `cat food`
   $ echo $menu
   apples cheddar chardonnay (символы возврата каретки за-
меняются на пробелы).

7.7. Переменные Shell - аргументы процедур

В начало страницы

   Это особый тип переменных, именуемых цифрами.
   
   Пример: $ dothis grapes apples pears (процедура).
   
   Тогда позиционные параметры (аргументы) этой команды дос-
тупны по именам:
   $1 = `grapes`
   $2 = `apples`
   $3 = `pears`
и т.д.  до $9.  Однако есть команда shift,  которая сдвигает
имена на остальные аргументы, если их больше 9 (окно шириной
9).

   Другой способ получить все аргументы (даже если их больше
9):
   $*, что эквивалентно $1$2 ...
   Количество аргументов  присваивается  другой  переменной:
$#(диез).  Наконец, имя процедуры - это $0; переменная $0 не
учитывается при подсчете $#.

7.8. Структурные операторы Shell

В начало страницы


   Кроме процедур,  в языке Shell имеются структурные опера-
торы типа "if-else" и "while-do". Программирование на Shell,
кроме написания процедур, используется для:

   - отработки  алгоритма  перед кодированием его в языках С
или  ФОРТРАН-77  (нет  компиляции,  линкирования,  загрузки,
простота отладки);
   - обучения принципам программирования непрограммистов.

7.9. Оператор цикла for


   Пусть имеется командный файл makelist (процедура)
   
   $ cat makelist
   sort +1 -2 people | tr -d -9 | pr -h Distribution | lpr.
   
   Если вместо одного файла people имеется несколько, нап-
ример:

   adminpeople, hardpeople, softpeople,...,
   
то необходимо  повторить  выполнение  процедуры с различными
файлами. Это возможно с помощью for - оператора.

 Синтаксис:
   for <переменная> in <список значений>
   do  <список команд>
   done
   
Ключевые слова  for, do, done  пишутся с начала строки.

   Пример (изменим процедуру makelist)
   for file in adminpeople, hardpeople, softpeople
   do
   Sort +1 -2 $file | tr ... | lpr
   done.
   
   Можно использовать метасимволы Shell в списке значений.
   Пример:
   
   for file in *people (для всех имен, кончающихся на people)
   do
   ...
   done.
   
   Если in опущено, то по умолчанию в качестве списка значе-
ний берется список аргументов процедуры, в которой содержит-
ся цикл,  а если цикл не в процедуре, то - список параметров
командной строки (то есть в качестве процедуры выступает ко-
манда).

   Пример: for file
           do
           ...
           done
   Для вызова makelist adminpeople hardpeople softpeople бу-
дет сделано то же самое.

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

В начало страницы

   Используем имена переменных,  представляющие значения па-
раметров процедуры:

   sort +1 -2 $1 | tr ... | lpr
   
   Пример неверного вызова:
   
   makelist (без параметров), где $1 неопределен.
   
   Исправить ошибку можно,  проверяя количество аргументов -
значение переменной $# посредством if - оператора.

   Пример: (измененной процедуры makelist):
   if test $# -eq 0
   then echo "You must give a filename"
   exit 1
   else sort +1 -2 $1 | tr ... | lpr
   fi
   
   Здесь test и exit - команды проверки (см.  раздел 7.11) и
выхода.

   Таким образом, синтаксис оператора if:
   
   if <если эта команда выполняется успешно, то>;
   then <выполнить все следующие команды до else или, если
его нет, до fi>;
   [else <иначе выполнить следующие команды до fi>]
Ключевые слова if, then, else и fi пишутся с начала строки.
   Успешное выполнение процедуры означает, что она возвраща-
ет значение true = 0 (zero) (неуспех - возвращаемое значение
не равно 0).

   Оператор exit 1 задает возвращаемое значение 1  для  неу-
дачного выполнения makelist и завершает процедуру.
   Возможны вложенные if.  Для else if есть сокращение elif,
которое одновременно сокращает fi.

7.11. Команда "test"

В начало страницы

   Не является частью Shell,  но применяется  внутри  Shell-
процедур.
   Имеется три типа проверок:
   
   - оценка числовых значений;
   - оценка типа файла;
   - оценка строк.
   
   Для каждого типа свои примитивы (операции op).
   Для чисел синтаксис такой:
   
   N op M, где N, M - числа или числовые переменные;
   op принимает значения: -eq, -ne, gt, -lt, -ge, -le (с
обычным смыслом, как, например, в ФОРТРАН).

   Для файла синтаксис такой:
  op filename,
где op принимает значения:
   -s (файл существует и не пуст);
   -f (файл, а не каталог);
   -d (файл-директория (каталог);
   -w (файл для записи);
   -r (файл для чтения).
   
   Для строк синтаксис такой:
   S op R, где S, R - строки или строковые переменные
или op1 S
   op принимает значения:
   = (эквивалентность);
   != (не эквивалентность);
   op1 принимает значения:
   -z (строка нулевой длины);
   -n (не нулевая длина строки).
   
   Наконец, несколько проверок разных типов могут быть  объ-
единены логическими операциями
   -a (AND) и -o (OR).
   
   Примеры:
   $ if test -w $2 -a -r S1
   > then cat $1 >> $2
   > else echo "cannot append"
   > fi
   $
   В некоторых вариантах ОС UNIX вместо команды test исполь-
зуются квадратные скобки, т.е. if [...] вместо if test
... .

7.12. Оператор цикла while

В начало страницы

   Синтаксис:
   
   while <команда>
   do
   <команды>
   done
   
   Если "команда" выполняется успешно,  то выполнить "коман-
ды", завершаемые ключевым словом done.

   Пример:
   if test $# -eq 0
   then echo "Usage: $0 file ..." > &2
        exit
   fi
   while test $# -gt 0
   do if test -s $1
   then echo "no file $1" > &2
   else sort + 1 - 2 $1 | tr -d ... (процедуры)
   fi
   shift (* перенумеровать аргументы *)
   done
   Процедуры выполняются над всеми аргументами.


7.13. Оператор цикла until

В начало страницы

   Инвертирует условие повторения по сравнению с while

   Синтаксис:
   
   until <команда>
   do
   <команды>
   done
   
   Пока "команда" не выполнится успешно,  выполнять команды,
завершаемые словом done.

   Пример:
   if test S# -eq 0
   then echo "Usage $0 file..." > &2
        exit
   fi
   until  test  S# -eq 0
   do
          if test -s $1
          then echo "no file $1" > &2
          else sort +1 -2 $1 | tr -d ... (процедура)
          fi
          shift                  (сдвиг аргументов)
   done
   Исполняется аналогично предыдущему.

7.14. Оператор выбора case

В начало страницы

   Синтаксис:
   
   case  in
   string1) <если string = string1, то выполнить все следую-
щие команды до ;; > ;;
   string2) <если string = string2, то выполнить все следую-
щие команды до ;; > ;;
   string3) ... и т.д. ...
   esac

   Пример:
   Пусть процедура имеет опцию -t, которая может быть подана
как первый параметр:
   .................
   together = no
   case  $1  in
   -t)  together = yes
        shift ;;
   -?)  echo  "$0: no option $1"
        exit ;;
        esac
        if test $together = yes
        then sort ...
        fi
   где ?  - метасимвол (если -?, т.е. "другая" опция, отлич-
ная  от  -t,  то ошибка).  Можно употреблять все метасимволы
языка Shell, включая ?, *, [-].
   Легко добавить (в примере) другие опции,  просто расширяя
case.

7.15. Использование временных файлов в каталоге /tmp

В начало страницы

   Это специальный каталог,  в котором все файлы доступны на
запись всем пользователям.
   Если некоторая процедура,  создающая временный файл,  ис-
пользуется несколькими пользователями, то необходимо обеспе-
чить уникальность имен создаваемых файлов. Стандартный прием
- имя временного файла $0$$,  где $0 - имя процедуры, а $$ -
стандартная переменная, равная уникальному идентификационно-
му номеру процесса, выполняющего текущую команду.
   Хотя администратор периодически удаляет временные файлы в
/tmp, хорошей практикой является их явное удаление после ис-
пользования.

7.16. Комментарии в процедурах

   Они начинаются с двоеточия :,  которое считается нуль-ко-
мандой,  а текст комментария - ее аргументом. Чтобы Shell не
интерпретировал  метасимволы  ($,  * и т.д.),  рекомендуется
заключать текст комментария в одиночные кавычки.
   В некоторых  вариантах  ОС  UNIX примечание начинается со
знака #.

7.17. Пример процедуры

В начало страницы

:'Эта процедура работает с файлами,  содержащими имена'
: 'и номера телефонов,'
:'сортирует их вместе или порознь  и печатает результат на'
:'экране или на принтере'
:'Ключи процедуры:'
:'-t (together) - слить и сортировать все файлы вместе'
:'-p (printer) - печатать файлы на принтере'
if test $# - eq 0
then  echo  "Usage: $ 0 file ... " > & 2
      exit
fi
together = no
print = no
while  test  $# -gt 0
do  case   $1  in
-t) together = yes
     shift ;;
-p) print = yes
     shift ;;
-?) echo "$0: no option $1"
     exit ;;
*)   if test $together = yes
     then sort -u +1 -2 $1 | tr ... > /tmp/$0$$
          if $print = no
          then cat /tmp/$0$$
          else lpr -c /tmp/$0$$
          fi
          rm /tmp/$0$$
          exit
     else if test -s $1
          then echo "no file $1" > &2
          else sort +1 -2 $1 | tr...> /tmp/$0$$
            if $print = no
            then cat /tmp/$0$$
            else lpr -c /tmp/$0$$
            fi
          rm /tmp/$0$$
          fi
          shift
     fi;;
     esac
done.

   Процедура проверяет число параметров $#, и если оно равно
нулю, завершается. В противном случае она обрабатывает пара-
метры (оператор case).  В качестве параметра может выступать
либо ключ  (символ,  предваряемый  минусом),  либо имя файла
(строка, представленная метасимволом *).  Если ключ  отличен
от допустимого  (метасимвол ?  отличен от t и p),  процедура
завершается. Иначе в зависимости от наличия ключей t и p вы-
полняются действия, заявленные в комментарии в начале проце-
дуры.

7.18. Обработка прерываний в процедурах

В начало страницы

   Если при выполнении процедуры получен  сигнал  прерывания
(от клавиши BREAK или DEL,  например), то все созданные вре-
менные файлы останутся неудаленными (пока это не сделает ад-
министратор) ввиду немедленного прекращения процесса.
   Лучшим решением является обработка прерываний внутри про-
цедуры оператором trap:
   Синтаксис: trap 'command arguments' signals...
   Кавычки формируют первый аргумент из  нескольких  команд,
разделенных точкой с запятой. Они будут выполнены, если воз-
никнет прерывание, указанное аргументами signals (целые):

   2 - когда вы прерываете процесс;
   1 - если вы "зависли" (отключены от системы)
и др.

   Пример (развитие  предыдущего):
   case $1 in
   .....
   *) trap 'rm /tmp/*; exit' 2 1 (удаление временных файлов)
   if test -s $1
   ..............
   rm /tmp/*
   Лучше было бы:
   trap 'rm /tmp/* > /dev/null; exit' 2 1
так как  прерывание  может  случиться  до  того,  как   файл
/tmp/$0$$  создан и аварийное сообщение об этом случае пере-
направляется на null-устройство.

7.19. Выполнение арифметических операций: expr

В начало страницы

   Команда expr вычисляет значение  выражения,  поданного  в
качестве  аргумента  и посылает результат на стандартный вы-
вод.  Наиболее интересным  применением  является  выполнение
операций над переменными языка Shell.

   Пример суммирования 3 чисел:
   $ cat sum3
   expr $1 + $2 + $3
   $ chmod 755 sum3
   $ sum3  13  49  2
   64
   $
   Пример непосредственного использования команды:
   $ expr 13 + 49 + 2 + 64 + 1
   129
   $
   В expr  можно применять следующие арифметические операто-
ры:  +, -, *, /, % (остаток). Все операнды и операции должны
быть разделены пробелами.
   Заметим, что знак умножения следует заключать  в  кавычки
(одинарные  или двойные),  например:  '*',  так как символ *
имеет в Shell специальный смысл.
   Более сложный пример expr в процедуре (фрагмент):
   num = 'wc -l < $1'
   tot = 100
   count = $num
   avint = 'expr $tot / $num'
   avdec = 'expr $tot % $num'
   while test $count -gt 0
   do ...
Здесь wc -l осуществляет подсчет числа строк в файле,  а да-
лее это число используется в выражениях.

7.20. Отладка процедур Shell

В начало страницы

   Имеются три средства, позволяющие вести отладку процедур.
   1) Размещение в теле процедуры команд echo для выдачи со-
общений, являющихся трассой выполнения процедуры.
   2) Опция -v (verbose = многословный) в команде Shell при-
водит к печати команды на экране перед ее выполнением.
   3) Опция -x (execute) в команде Shell приводит  к  печати
команды на экране по мере ее выполнения с заменой всех пере-
менных их значениями; это наиболее мощное средство.


<<< Оглавление Страницы: 7  8 >>>