Online Documentation Server
 ПОИСК
ods.com.ua Web
 КАТЕГОРИИ
Home
Programming
Net technology
Unixes
Security
RFC, HOWTO
Web technology
Data bases
Other docs

 

 ПОДПИСКА

 О КОПИРАЙТАХ
Вся предоставленная на этом сервере информация собрана нами из разных источников. Если Вам кажется, что публикация каких-то документов нарушает чьи-либо авторские права, сообщите нам об этом.




Previous | Содержание | Next

ВВЕДЕНИЕ В 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 приводит к печати команды на экране по мере ее выполнения с заменой всех пере- менных их значениями; это наиболее мощное средство.

Previous | Содержание | Next



With any suggestions or questions please feel free to contact us