Программирование на shell (UNIX), часть 4


		 5.1. Команда test ("[ ]")

     Команда  test  проверяет  выполнение  некоторого  условия. С

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

выбора и цикла языка shell.

     Два возможных формата команды:

     test условие

или

     [ условие ]

     мы  будем  пользоваться  вторым вариантом, т.е. вместо того,

чтобы писать перед условием слово "test", будем заключать условие

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

     На  самом  деле  shell  будет  распознавать  эту  команду по

открывающей  скобке  "[",  как  слову(!), соответсвующему команде

"test".    Уже    этого    достаточно,   чтобы   предупредить   о

распространенной ошибке начинающих: Между скобками и содержащимся

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

     Пробелы  должны быть и между значениями и символом сравнения

или  операции  (как,  кстати,  и  в  команде "expr"). Не путать с

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

     В shell используются условия различных "типов".

     УСЛОВИЯ ПРОВЕРКИ ФАЙЛОВ:

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

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

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

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

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

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

     Примеры. Вводя с клавиатуры командные строки в первом случае

получим  подтверждение  (код  завершения  "0"),  а  во  втором  -

опровержение (код завершения "1"). "specific" - имя существующего

файла.

     [ -f specific ] ; echo $?

     0

     [ -d specific ] ; echo $?

     1

     УСЛОВИЯ ПРОВЕРКИ СТРОК:

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

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

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

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

     Примеры.

     x="who is who"; export x; [ "who is who" = "$x" ]; echo $?

     0

     x=abc ; export x ; [ abc = "$x" ] ; echo $?

     0

     x=abc ; export x ; [ -n "$x" ] ; echo $?

     0

     x="" ; export x ; [ -n "$x" ] ; echo $?

     1

     ВАЖНОЕ  ЗАМЕЧАНИЕ.  Команда  "test"  дает  значение "истина"

(т.е.  код завершения "0") и просто если в скобках стоит непустое

слово.

      [ privet ] ; echo $?

      0

      [ ] ; echo $?

      1

     Кроме  того,  существуют  два  стандартных значения условия,

которые  могут  использоваться вместо условия (для этого не нужны

скобки).

      true ; echo $?

      0

      false ; echo $?

      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".

     То  есть  в данном случае команда "test" воспринимает строки

символов  как  целые (!) числа. Поэтому во всех остальных случаях

"нулевому"  значению  соответствует  пустая  строка.  В данном же

случае,  если  надо  обнулить  переменную,  скажем,  "x",  то это

достигается присваиванием "x=0".

     Примеры.

     x=abc ; export x ; [ abc -eq "$x" ] ; echo $?

     "[": integer expression expected before -eq

     x=321 ; export x ; [ 321 -eq "$x" ] ; echo $?

     0

     x=3.21 ; export x ; [ 3.21 -eq "$x" ] ; echo $?

     "[": integer expression expected before -eq

     x=321 ; export x ; [ 123 -lt "$x" ] ; echo $?

     0

     СЛОЖНЫЕ УСЛОВИЯ:

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

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

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

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

     ПРЕДУПРЕЖДЕНИЕ. Не забывайте о пробелах.

     Примеры.

      [ ! privet ] ; echo $?

      1

     x=privet; export x; [ "$x" -a -f specific ] ; echo $?

     0

     x="";export x; [ "$x" -a -f specific ] ; echo $?

     1

     x="";export x; [ "$x" -a -f specific -o privet ] ; echo $?

     0

     x="";export x; [ "$x" -a -f specific -o ! privet ] ; echo $?

     1

     СОВЕТ. Не злоупотреблять сложными условиями.

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

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

    if  условие

      then  список

	 [elif  условие

	  then  список]

      [else  список]

    fi

     Здесь  "elif"  сокращенный  вариант  от "else if" может быть

использован   наряду   с   полным,   т.е.   допускается  вложение

произвольного  числа  операторов  "if" (как и других опреаторов).

Разумеется  "список"  в  каждом  случае должен быть осмысленный и

допустимый в данном контексте.

     Конструкции

     [elif  условие

      then  список]

и

     [else  список]

     не  являются  обязательными (в данном случае для указания на

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

путать с квадратными скобками команды "test"!).

     Самая усеченная структура этого оператора

    if   условие

      then  список

    fi

     если  выполнено  условие  (как  правило  это ком получен код

завершения "0", то выполняется "список", иначе он пропускается.

     Обратите  внимание,  что  структура  обязательно завершается

служебным  словом  "fi".  Число  "fi", естественно, всегда должно

соответсвовать числу "if".

     Примеры.

     Пусть написан расчет "if-1"

     if [ $1 -gt $2 ]

	then pwd

	else echo $0 : Hello!

     fi

     Тогда вызов расчета

     if-1 12 11

даст

     /home/sae/STUDY/SHELL

а

     if-1 12 13

даст

     if-1 : Hello!

     Возможно  использовать  в  условии  то  свойство  shell, что

команды  могут  выдавать различный код завершения. Это напоминает

приемы программирования на Си. Пусть расчет "if-2" будет

     if a=`expr "$1" : "$2"`

	then echo then a=$a code=$?

	else echo else a=$a code=$?

     fi

тогда вызов

     if-2  by by

даст

     then a=2 code=0

а

     if-2  by be

даст

     else a=0 code=1

     Еще пример на вложенность

     ###

     # if-3: Оценка достижений

     echo -n " А какую оценку получил на экзамене?: "

     read z

     if [ $z = 5 ]

	then echo  Молодец !

	elif [ $z = 4 ]

	     then echo  Все равно молодец !

	     elif [ $z = 3 ]

		  then echo  Все равно !

		  elif [ $z = 2 ]

		       then echo  Все !

		       else echo   !

     fi

     Можно  обратить  внимание на то, что желательно использовать

сдвиги  при  записи  программ,  чтобы  лучше выделить вложенность

структур.

	       5.3. Оператор выбова ("case")

     Оператор выбора "case" имеет структуру:

     case   строка  in

	шаблон)  список команд;;

	шаблон)  список команд;;

	    ...

     esac

     Здесь  "case" "in" и "esac" - служебные слова. "Строка" (это

может  быть  и  один  символ)  сравнивается  с  "шаблоном". Затем

выполняется  "список  команд" выбранной строки. Непривычным будет

служебное   слово   "esac",  но  оно  необходимо  для  завершения

структуры.

     Пример.

     ###

     # case-1: Структура "case".

     #         Уже рассматривавшийся в связи со

     #         структурой "if" пример проще и

     #         нагляднее можно реализовать с

     #         помощью структуры "case".

     echo -n " А какую оценку получил на экзамене?: "

     read z

     case $z in

	5) echo Молодец !            ;;

	4) echo Все равно молодец !  ;;

	3) echo Все равно !          ;;

	2) echo Все !                ;;

	*) echo  !                   ;;

     esac

     Непривычно  выглядят  в конце строк выбора ";;", но написать

здесь  ";"  было  бы  ошибкой. Для каждой альтернативы может быть

выполнено  несколько  команд.  Если  эти команды будут записаны в

одну  строку,  то символ ";" будет использоваться как разделитель

команд.

     Обычно  последняя  строка  выбора  имеет  шаблон  "*", что в

структуре   "case"   означает   "любое   значение".   Эта  строка

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

(здесь  $z) ни с одним из ранее записанных шаблонов, ограниченных

скобкой ")". Значения просматриваются в порядке записи.

     ###

     # case-2:  Справочник.

     #          Для различных фирм по имени выдается

     #          название холдинга, в который она входит

     case $1 in

	     ONE|TWO|THREE) echo Холдинг: ZERO    ;;

		   MMM|WWW) echo Холдинг: Not-Net ;;

	 Hi|Hello|Howdoing) echo Холдинг: Привет! ;;

			 *) echo Нет такой фирмы  ;;

     esac

     При вызове "case-2 Hello" на экран будет выведено:

     Холдинг: Привет!

     А при вызове "case-2 HELLO" на экран будет выведено:

     Нет такой фирмы

     Коль  скоро слово "case" переводится как "выбор", то это как

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

реализации простейших меню.

     ###

     # case-3: Реализация меню с помощью команды "case"

     echo "Назовите файл, а затем (через пробел)

     наберите цифру, соответствующую требуемой

     обработке:

	    1 - отсортировать

	    2 - выдать на экран

	    3 - определить число строк  "

     read x y  # x - имя файла, y - что сделать

     case $y in

	1) sort
< $x               ;;

	2) cat
< $x               ;;

	3) wc -l
< $x               ;; 	*) echo " 		   Мы не знаем 		   такой команды ! " ;;      esac      Разумеется,  желания  могут  быть  более  сложные и на месте отдельных  команд могут быть последовательности команд или вызовы более сложных расчетов.      Напишем  команду  "case-4",  которая  добавляет информацию к файлу,  указанного  первым  параметром  (если  параметр один), со стандартного  входа, либо (если 2 параметра) из файла, указанного в качестве первого параметра:      ###      # case-4: Добавление в файл.      #         Использование стандартной переменной.      # "$#" -  число параметров при вводе расчета      # ">
>
" -  перенаправление с добавлением в файл

     case $# in

	  1) cat >
>
 $1                           ;;

	  2) cat >
>
 $2
< $1                      ;;

	  *) echo "Формат: case-4 [откуда] куда" ;;

     esac

     "$1"  (при  "$#=1")  -  это  имя файла, в который происходит

добавление со стандартного входа.

     "$1"  и  "$2"  (при  $#=2)  - это имена файлов , из которого

("$1") и в который ("$2") добавлять.

     Во  всех  других случаях (*) выдается сообщение о том, каким

должен быть правильный формат команды.