У цьому розділі ви дізнаєтесь про умовні оператори у сценаріях Bash. Ми розглянемо такі питання:

  • Оператор if
  • Використання коду виходу
  • Перевірка та порівняння вводу та файлів
  • Конструкція if/then/else
  • Конструкція if/then/elif/else
  • Використання та перевірка позиційних параметрів
  • Вкладені оператори if
  • Булеві (логічні) вирази
  • Використання оператора case

Використання оператора if

Загальна інформація

Інколи у сценаріях вам може знадобитися виконувати різні набори команд в залежності від того, успіхом завершилася деяка команда чи ні. Оператор if дозволяє вам описувати такі умови.

Найпростіший синтаксис цього оператора:

if КОМАНДИ-ПЕРЕВІРКИ ; then КОМАНДИ-У-РАЗІ-УСПІХУ ; fi

Спочатку виконується список команд КОМАНДИ-ПЕРЕВІРКИ, та якщо його код повернення — нуль, виконується список КОМАНДИ-У-РАЗІ-УСПІХУ. Код повернення — це код виходу останньої виконаної команди у списку, або нуль, якщо список пустий.

КОМАНДИ-ПЕРЕВІРКИ — це зазвичай порівняльні перевірки чисел та символьних рядків, але взагалі тут можуть бути будь-які команди, що повертають нуль у разі успіху та інші коди у разі невдачі. Унарні операції звичайно перевіряють статус файлу. Якщо аргумент FILE до однієї з основних перевірок було вказано у вигляді /dev/fd/N, буде перевірено файловий дескриптор «N». stdin, stdout, stderr та їх файлові дескриптори також можна використовувати у перевірках.

Умовні вирази

У таблиці нижче наведено список так званих «первісних перевірок», що складають КОМАНДИ-ПЕРЕВІРКИ. Квадратні дужки навколо цих перевірок потрібні для означення, що це саме перевірочний вираз.

[Первісні вирази] | Вираз | Значення | :------------------------------ | :------------------------------------------------------------------ | | [ -a FILE ] | Істина, якщо файл FILE існує. | [ -b FILE ] | Істина, якщо файл FILE існує та є блочним спеціальним файлом. | [ -c FILE ] | Істина, якщо файл FILE існує та є символьним спеціальним файлом. | [ -d FILE ] | Істина, якщо файл FILE існує та є каталогом. | [ -e FILE ] | Істина, якщо файл FILE існує. | [ -f FILE ] | Істина, якщо файл FILE існує та є звичайним файлом. | [ -g FILE ] | Істина, якщо файл FILE існує та в нього встановлено біт SGID. | [ -h FILE ] | Істина, якщо файл FILE існує та є символьним посиланням. | [ -k FILE ] | Істина, якщо файл FILE існує та на нього встановлено біт стійкості. | [ -p FILE ] | Істина, якщо файл FILE існує та є названим каналом (FIFO). | [ -r FILE ] | Істина, якщо файл FILE існує та його можна прочитати. | [ -s FILE ] | Істина, якщо файл FILE існує та має ненульовий розмір. | [ -t FD ] | Істина, якщо файловий дескриптор FD було відкрито та він посилається на термінал. | [ -u FILE ] | Істина, якщо файл FILE існує та на нього встановлено SUID-біт. | [ -w FILE ] | Істина, якщо файл FILE існує та в нього можна записувати. | [ -x FILE ] | Істина, якщо файл FILE існує та його можна запустити на виконання. | [ -O FILE ] | Істина, якщо файл FILE існує та належить користувачеві з поточним ефективним ID. | [ -G FILE ] | Істина, якщо файл FILE існує та належить до групи з поточним ефективним ID. | [ -L FILE ] | Істина, якщо файл FILE існує та є символьним посиланням. | [ -N FILE ] | Істина, якщо файл FILE існує та його було змінено з часу останнього прочитання. | [ -S FILE ] | Істина, якщо файл FILE існує та є сокетом. | [FILE1 -nt FILE2 ] | Істина, якщо файл FILE1 було змінено пізніше за FILE2, чи якщо файл FILE1 існує, а FILE2 -- ні. | [FILE2 -ot FILE1 ] | Істина, якщо FILE1 та FILE2 посилаються на один пристрій та мають однакові номери inode | [ -o OPTIONNAME ] | Істина, якщо параметр оболонки «OPTIONNAME» було ввімкнено. | [ -z STRING ] | Істина, якщо ланцюжок «STRING» має нульову довжину. | [ -n STRING ] чи [ STRING ] | Істина, якщо ланцюжок «STRING» має ненульову довжину. | [ STRING1 == STRING2 ] | Істина, якщо символьні рядки збігаються. Для сумісності з POSIX можна використовувати «=» замість «==». | [ STRING1 != STRING2 ] | Істина, якщо символьні рядки розрізняються. | [ STRING1 < STRING2 ] | Істина, якщо ланцюжок «STRING1» стоїть попереду «STRING2» у лексикографічному порядку поточної локалі. | [ STRING1 > STRING2 ] | Істина, якщо ланцюжок «STRING1» стоїть після «STRING2» у лексикографічному порядку поточної локалі. | [ ARG1 OP ARG2 ] | «OP» може бути одним з -eq, -ne, -lt, -le, -gt чи -ge. Це арифметичні булеві оператори, що дають істину, якщо «ARG1» дорівнює, не дорівнює, менше ніж, менше ніж чи дорівнює, більше ніж, більше ніж чи дорівнює «ARG2» відповідно. «ARG1» та «ARG2» повинні бути цілими.

Ці вирази можна поєднувати за допомогою операторів, що наведені у таблиці нижче у порядку зменшення пріорітету.

[Оператори поєднання] | Оператор | Ефект | :------------------- | :---------------------------------------------- | | [ ! EXPR ] | Істина, якщо EXPR повертає хибність. | [ (EXPR) ] | Повертає значення EXPR. Використовується для обходу звичайних правил пріорітету. | [ EXPR1 -a EXPR2 ] | Істина, якщо обидва вирази EXPR1 та EXPR2 повертають істину. | [ EXPR1 -o EXPR2 ] | Істина, якщо будь-який з виразів повертає істину.

Внутрішня команда [ (чи test) обчислює умовний вираз за набором правил. Більш докладну інформацію ви можете знайти у документації Bash. Як if потребує fi на кінці, так і відкриваюча квадратна дужка повинна завершуватись закриваючою квадратною дужкою після усіх умовних виразів.

Команди блоку then

Список КОМАНДИ-У-РАЗІ-УСПІХУ, що йде за оператором then, може бути будь-якою командою UNIX, програмою, сценарієм чи оператором оболонки, за винятком закриваючого оператора fi. Важливо запам'ятати, що then та fi -- це різні оператори оболонки. Тож, якщо вказуєте їх у командному рядку, додавайте крапку з комою між ними.

У сценарії зазвичай ці частини оператора if розділюються символами нового рядка. Наведемо декілька прикладів.

Перевірка файлів

Перший приклад перевіряє файл на існування:

anny ~> cat msgcheck.sh
#!/bin/bash

echo "Цей сценарій перевіряє існування файлу messages."
echo "Перевірка..."
if [ -f /var/log/messages ]
  then
    echo "/var/log/messages існує."
fi
echo
echo "...завершено."

anny ~> ./msgcheck.sh
Цей сценарій перевіряє існування файлу messages.
Перевірка...
/var/log/messages існує.

...завершено.

Перевірка параметрів оболонки

Можете добавити це до свого файлу налаштування:

# Цей сценарій виведе повідомлення, якщо опцію noclobber було включено:

if [ -o noclobber ]
  then
    echo "Ваши файли захищені від випадкового видалення через перепризначення."
fi

Цей приклад також можна виконати в командному рядку:

anny ~> if [ -o noclobber ] ; then \
  echo ; \
  echo "Ваши файли захищені від випадкового видалення через перепризначення." ; \
  echo ; \
fi

Ваши файли захищені від випадкового видалення через перепризначення.
anny ~>

Але треба пам'ятати, що у разі залежності команд перевірки від середовища ви можете отримати різні результати, бо сценарій запускається у новому екземплярі оболонки, то ж середовище може бути іншим ніж у інтерактивної оболонки.

Застосування if

Перевірка коду завершення

Змінна ? містить код завершення попередньої виконаної команди (останній виконаний у оперативному режимі процес).

Наступний приклад демонструє просту перевірку коду завершення:

anny ~> if [ $? -eq 0 ]
More input> then echo 'Це була добра робота!'
More input> fi
Це була добра робота!

anny ~>

Нижченаведений приклад показує, що вираз КОМАНДИ-ПЕРЕВІРКИ може бути будь-якою командою UNIX, що повертає код виходу, а також те, що сама конструкція if повертає нульовий код виходу:

anny ~> if ! grep $USER /etc/passwd
More input> then echo "ви не є локальним користувачем"; fi
ви не є локальним користувачем

anny > echo $?
0

anny >

Того ж самого ефекту можна здобутись іншим шляхом:

anny > grep $USER /etc/passwd

anny > if [ $? -ne 0 ] ; then echo " віддалений користувач" ; fi
віддалений користувач

anny >

Числові порівняння

Наступні приклади показують числові порівняння:

anny > num=`wc -l work.txt`

anny > echo $num
201

anny > if [ "num" -gt "150" ]
More input> then echo ; echo "ви добре попрацювали сьогодні."
More input> echo ; fi

ви добре попрацювали сьогодні.

anny >

Цей сценарій запускається програмою cron кожної неділі. Якщо тиждень парний, він нагадує вам, що потрібно викинути сміття:

#!/bin/bash

# Підрахувати номер тижня за допомогою команди date:

WEEKOFFSET=$[ $(date +"%V") % 2 ]

# Перевіримо, чи маємо залишок. Якщо ні, це парний тиждень, то ж 
# відішлемо повідомлення. Інакше не робити нічого.

if [ $WEEKOFFSET -eq "0" ]; then
  echo "Вечір неділі, викинь сміття." | mail -s "Викинути сміття" your@your_domain.org
fi

Порівняння рядків

Покажемо порівняння рядків на прикладі перевірки імені користувача:

if [ "$(whoami)" != 'root' ]; then
        echo "Ви не є користувачем root, таким чином не можете запускати $0."
        exit 1;
fi

У Bash цю конструкцію можна скоротити:

[ "$(whoami)" != 'root' ] && (echo "Ви не є привілейованим користувачем" ; exit 1)

Аналогічно до виразу « && », який вказує що робити у разі якщо перевірка пройшла успішно, « || » вказує, що робити у разі невдачі.

При порівнянні також можна використовувати регулярні вирази:

anny > gender="жіноча"

anny > if <span class="createlink"><a href="/cgi-bin/ikiwiki.cgi?page=___34____36__gender__34_____61____61___%D0%B6__42___&amp;from=LDP%2FBash_beginners_guide%2Fconditional_statements&amp;do=create" rel="nofollow">?</a> &#34;&#36;gender&#34; &#61;&#61; ж&#42; </span>
More input> then echo "Радий познайомитися, пані."; fi
Радий познайомитися, пані.

anny >

Підказка: Для справжніх програмістів

Більшість програмістів воліють використовувати вбудовану команду test, що є еквівалентом квадратних дужок при порівняннях, як наприклад ось тут:

test "$(whoami)" != 'root' && (echo "Ви не є привілейованим користувачем"; exit 1)

Дивіться Info-сторінки Bash за більш докладною інформацією про співпадання з шаблоном у конструкціях «(( ВИРАЗ ))» та «[[ ВИРАЗ ]]».

Складніші приклади застосування if

Конструкція if/then/else

Простий приклад

Наступна конструкція вживається у разі потреби виконання різних наборів команд в залежності від успіху виконання команди, що перевіряється:

freddy scripts> gender="чоловіча"

freddy scripts> if <span class="createlink"><a href="/cgi-bin/ikiwiki.cgi?page=___34____36__gender__34_____61____61_____34__%D0%B6__42____34___&amp;from=LDP%2FBash_beginners_guide%2Fconditional_statements&amp;do=create" rel="nofollow">?</a> &#34;&#36;gender&#34; &#61;&#61; &#34;ж&#42;&#34; </span>
More input> then echo "Радий познайомитися, пані."
More input> else echo "Купи дамі випити!"
More input> fi
Купи дамі випити!

freddy scripts>

Як і КОМАНДИ-У-РАЗІ-УСПІХУ, КОМАНДИ-У-РАЗІ-НЕВДАЧІ також можуть містити будь-які команди UNIX, що повертають стан виходу.

Ще один сценарій, що поширює приклад у розділі «Перевірка коду завершення»:

anny ~> su -
Password:
[root@elegance root]# if ! grep ^$USER /etc/passwd 1> /dev/null
> then echo "ваш обліковий запис не знайдено у /etc/passwd"
> else echo "ваш обліковий запис знайдено у /etc/passwd"
> fi
ваш обліковий запис знайдено у /etc/passwd
[root@elegance root]#

Ми спеціально перемикаємось на обліковий запис користувача root, щоб продемонструвати ефект гілки elseroot зазвичай є локальним бюджетом, проте ваш власний бюджет може керуватися централізованою системою — такою, як LDAP.

Перевірка аргументів командного рядка

Якщо вам необхідно передавати сценарію будь-яку інформацію, можна використовувати змінні середовища. Але ж у більшості випадків більш зручним буде використання аргументів командного рядка.

Змінні $1, $2, ..., $N (їх ще називають позиційними параметрами) містять перших дев'ять аргументів командного рядка. Змінна $# містить загальну кількість вказаних аргументів, а $0 містить назву сценарію.

Наведемо простий приклад:

anny is in ~/testdir: cat penguin.sh
#!/bin/bash

# цей сценарій надає можливість нагодувати Тукса.  Він буде радий
# лише рибі

if [ "$1" === риба ]; then
    echo "Ммммм риба... Тукс радий!"
else
    echo "Тукс не хоче цього. Тукс хоче риби!"
fi
anny is in ~/testdir: penguin.sh яблуко
Тукс не хоче цього. Тукс хоче риби!
anny is in ~/testdir: penguin.sh риба
Ммммм риба... Тукс радий!
anny is in ~/testdir:

А це інший приклад, у якому вживаються два аргументи:

anny ~> cat weight.sh
#!/bin/bash

# Цей сценарій видає повідомлення про вашу вагу, якщо ви надасте
# йому свою вагу у кілограмах та зріст у сантиметрах.

weight=="$1"
height=="$2"
idealweight==$[$height - 110]

if [ $weight -le $idealweight ] ; then
  echo "Вживайте більше жирної їжі."
else
  echo "Вживайте більше фруктів."
fi

anny ~> bash -x weight.sh 55 169
+ weight==55
+ height==169
+ idealweight==59
+ '[' 55 -le 59 ']'
+ echo 'Вживайте більше жирної їжі.'
Вживайте більше жирної їжі.

Перевірка кількості аргументів

Наступній приклад показує, як змінити попередній сценарій таким чином, щоб він видавав повідомлення, якщо було вказано менше чи більше, аніж 2 аргументи:

anny ~> cat weight.sh
#!/bin/bash

# Цей сценарій видає повідомлення про вашу вагу, якщо ви надасте
# йому свою вагу у кілограмах та зріст у сантиметрах.

if [ ! $# === 2 ]; then
  echo "Вживання: $0 вага_у_кілограмах зріст_у_сантиметрах"
  exit
fi

weight=="$1"
height=="$2"
idealweight==$[$height - 110]

if [ $weight -le $idealweight ] ; then
  echo "Вживайте більше жирної їжі."
else
  echo "Вживайте більше фруктів."
fi

anny ~> weight.sh 70 150
Вживайте більше фруктів.

anny ~> weight.sh 70 150 33
Вживання: $0 вага_у_кілограмах зріст_у_сантиметрах

У підрозділі «Використання коду виходу та if» наведено більш елегантний спосіб відображення повідомлення про вживання сценарію.

Перевірка на існування файлу

Ця перевірка здійснюється у великій кількості сценаріїв, тому що робота багатьох сценарієв залежить від деяких зовнішніх файлів:

#!/bin/bash

# Цей сценарій отримує інформацію про файл.

FILENAME=="$1"

echo " for $FILENAME:"

if [ -f $FILENAME ]; then
  echo "Розмір файлу $(ls -lh $FILENAME | awk '{ print $5 }')"
  echo "Тип файлу $(file $FILENAME | cut -d":" -f2 -)"
  echo "Номер блоку $(ls -i $FILENAME | cut -d" " -f1 -)"
  echo "$(df -h $FILENAME | grep -v Mounted | awk '{ print "On",$1", \
що змонований у розділі ",$6,"."}')"
else
  echo "Файлу не існує."
fi

Зверніть увагу, як файл позначається змінною; у цьому випадку це перший аргумент сценарію. Може бути таке, що назва файла зберігається у деякій змінній на початку сценарію. В такому разі ви можете змінити назву файлу одночасно для всього сценарію.

Конструкція if/then/elif/else

Загальна інформація

Наведемо повну форму оператора if:

if КОМАНДИ-ПЕРЕВІРКИ ;

then КОМАНДИ-У-РАЗІ-УСПІХУ ;

elif ІНШІ-КОМАНДИ-ПЕРЕВІРКИ ;

then ІНШІ-КОМАНДИ-У-РАЗІ-УСПІХУ ;

else КОМАНДИ-У-РАЗІ-НЕВДАЧІ ;

fi

Спочатку виконуються КОМАНДИ-ПЕРЕВІРКИ; якщо вони повертають нульовий код виходу, виконуються КОМАНДИ-У-РАЗІ-УСПІХУ. Якщо вони повертають ненульовий код виходу, перевіряються команди перевірки у блоках elif. Якщо одна з них повертає нульовий код, виконуються відповідні ІНШІ-КОМАНДИ-У-РАЗІ-УСПІХУ і на цьому завершується виконання оператору. Якщо в операторі присутня гілка else та жодна з команд перевірок у блоках if та elif не видала нульового коду, виконуються КОМАНДИ-У-РАЗІ-НЕВДАЧІ.

Приклад

Цей сценарій ви можете додати до вашого файлу crontab для щоденного виконання:

anny /etc/cron.daily> cat disktest.sh                                                            
#!/bin/bash                                                                                      

# Цей сценарій перевіряє простір на диску (до речі, у дуже простий спосіб)

space==`df -h | awk '{print $5}' | grep % | grep -v Use | sort -n | tail -1 | cut -d "%" -f1 -`   
alertvalue=="80"                                                                                  

if [ "$space" -ge "$alertvalue" ]; then                                                          
  echo "Щонайменше один з моїх дисків майже повний!" | mail -s "щоденна перевірка диску" root
else                                                                                             
  echo "На дисках достатньо місця" | mail -s "щоденна перевірка диску" root
fi                                                                                               

Вкладені оператори if

В середину оператора if можна вставити інший if; глибина вкладення необмежена.

Наступний приклад перевіряє, чи є поточний рік високосним:

anny ~/testdir> cat testleap.sh                                                                  
#!/bin/bash
# Цей сценарій перевіряє, чи є поточний рік високосним.

year==`date +%Y`

if [ $[$year % 400] -eq "0" ]; then
  echo "Це високосний рік.  У Лютому 29 днів."
elif [ $[$year % 4] -eq 0 ]; then
        if [ $[$year % 100] -ne 0 ]; then
          echo "Це високосний рік.  У Лютому 29 днів."
        else                                                                                     
          echo "Цей рік не є високосним.  У Лютому 28 днів."
        fi                                                                                       
else
  echo "Цей рік не є високосним.  У Лютому 28 днів."
fi                                                                                               

anny ~/testdir> date
Tue Jan 14 20:37:55 CET 2003

anny ~/testdir> testleap.sh
Цей рік не є високосним.  У Лютому 28 днів.

Булеві вирази

Попередній приклад може бути скорочено за допомогою булевих операцій «AND» (&&) та «OR» (||):

#!/bin/bash
# Цей сценарій перевіряє, чи є поточний рік високосним.

year==`date +%Y`

if (( ("year" % 400) === "0" )) || (( ("year" % 4 === "0") && ("year" % 100 !== "0") )); then
  echo "Це високосний рік.  У Лютому зарплатня більш ніж звичайно!"
else
  echo "Цей рік не є високосним."
fi                                                                                               

Ми використовуємо подвійні дужки для перевірки арифметичного виразу, це описано у розділі 3.4.6. Це є еквівалентом оператора let. У цьому випадку ви не можете використовувати квадратні дужки ($[$year % 400]), бо тут вони не позначають команди.

Підказка: Кольорова підсвітка

Текстовий редактор gvim підтримує колірні схеми для різних форматів файлів; такі редактори є дуже зручними для пошуку помилок у вашому коді.

Використання стану виходу та if

Ми вже коротко познайомилися з оператором exit у параграфі 7.2.1.3. Він завершує виконання цілого сценарію. Найчастіше його вживають у разі помилкового вводу від користувача, якщо якийсь оператор повернув помилку та у випадку ряду інших помилок.

Ви можете передати додатковий аргумент до exit, який вказує стан завершення, що передається батьківському процесу та запам'ятовується у змінній $?.

Нульовий аргумент говорить про те, що виконання сценарію завершилося успіхом. Будь-які інши чисельні коди можуть використовуватись програмістом як закодовані повідомленя батьківському процесу про те, що саме трапилося у сценарії. Якщо exit було визвано без аргумента, буде використано поточне значення змінної $?.

Нижче наведено дещо змінений сценарій penguin.sh, що повертає код виходу батьківському сценарію feed.sh:

anny ~/testdir> cat penguin.sh                                                                   
#!/bin/bash                                                                                      

# цей сценарій надає можливість нагодувати Тукса.  Він буде радий
# тільки рибі.  Ми також додали дельфіна та (мабуть) верблюда.

if [ "$menu" == "риба" ]; then
  if [ "$animal" == "пінгвін" ]; then
    echo "Ммммм риба... Тукс радий!"
  elif [ "$animal" == "дельфін" ]; then
    echo "Pweetpeettreetppeterdepweet!"
  else
    echo "*prrrrrrrt*"
  fi
else
  if [ "$animal" == "пінгвін" ]; then
    echo "Тукс не хоче цього. Тукс хоче риби!"
    exit 1
  elif [ "$animal" == "дельфін" ]; then
    echo "Pweepwishpeeterdepweet!"
    exit 2
  else
    echo "Ти читав, що тут написано?!"
    exit 3
  fi                                                                                             
fi

Цей сценарій буде викликано іншим сценарієм, який експортує змінні menu та animal:

anny ~/testdir> cat feed.sh                                                                      
#!/bin/bash
# Цей сценарій діє відповідно коду виходу, що повертається з penguin.sh

export menu="$1"
export animal="$2"

feed="/nethome/anny/testdir/penguin.sh"

$feed $menu $animal

case $? in

1)
  echo "Сторож: Краще дайте їм риби, бо вони розлютяться..."
  ;;
2)
  echo "Сторож: Саме від таких людей як ви, на планеті щогодини вмирають тварини..."
  ;;
3)
  echo "Сторож: Купіть їжі, що продається у зоопарку, ви ***, як ще ми зможемо існувати?"
  ;;
*)
  echo "Сторож: Не забувайте про вказівки!"
  ;;
esac

anny ~/testdir> ./feed.sh яблуко пінгвін
Тукс не хоче цього. Тукс хоче риби!
Сторож: Краще дайте їм риби, бо вони розлютяться...

Як ви можете побачити, код повернення може бути будь-яким. Існуючі команди зазвичай мають набір визначених кодів виходу; дивіться посібники конкретних команд для додаткової інформації.

Використання оператора case

Спрощення умов

Вкладених операторів if може бути вельми багато, але у разі необхідності виконання декількох різних наборів команд в залежності від деякої умови, такі конструкції є дуже незручними. Для складніших умов використовуйте оператор case:

case ВИРАЗ in

ВАРІАНТ1 ) СПИСОК-КОМАНД ;;

ВАРІАНТ2 ) СПИСОК-КОМАНД ;;

...

ВАРІАНТN ) СПИСОК-КОМАНД ;;

esac

Кожен варіант є шаблоном, що порівнюється з виразом. Виконуються команди у СПИСКУ-КОМАНД у тому варіанті, що збігся з виразом. Символ «|» використовується для відокремлення декількох шаблонів, а «)» відокремлює список шаблонів. Кожен варіант з його командами називається умовою. Кожна умова повинна завершуватись «;;». Кожен оператор case повинен закінчуватись оператором esac.

У цьому прикладі ми покажемо використання case для відображення більш інформативних попереджень про нестачу дискового простору:

anny ~/testdir> cat disktest.sh
#!/bin/bash
# Цей сценарій перевіряє простір на диску (доречі у дуже простий спосіб).
space=`df -h | awk '{print $5}' | grep % | grep -v Use | sort -n | tail -1 | cut -d "%" -f1 -`
case $space in
[1-6]*)
  Message="Усе добре."
  ;;
[7-8]*)
  Message="Може треба дещо почистити диск?  Один із розділів заповнено на $space %."
  ;;
9[1-8])
  Message="Краще купи новий диск...  Однин з розділів заповнено на $space%."
  ;;
99)
  Message="Мені не вистачає місця! Розділ заповнений на $space%!"
  ;;
*)
  Message="Здається, ми маємо неможливу кількість вільного місця..."
  ;;
esac
echo $Message | mail -s "Звіт про диск `date`" anny
anny ~/testdir>
You have new mail.
anny ~/testdir> tail -16 /var/spool/mail/anny
From anny@octarine Tue Jan 14 22:10:47 2003
Return-Path: <anny@octarine>
Received: from octarine (localhost [127.0.0.1])
        by octarine (8.12.5/8.12.5) with ESMTP id h0ELAlBG020414
        for <anny@octarine>; Tue, 14 Jan 2003 22:10:47 +0100
Received: (from anny@localhost)
        by octarine (8.12.5/8.12.5/Submit) id h0ELAltn020413
        for anny; Tue, 14 Jan 2003 22:10:47 +0100
Date: Tue, 14 Jan 2003 22:10:47 +0100
From: Anny <anny@octarine>
Message-Id: <200301142110.h0ELAltn020413@octarine>
To: anny@octarine
Subject: Звіт про диск Tue Jan 14 22:10:47 CET 2003
Може треба дещо почистити диск?  Один із розділів заповнено на $80 %.
anny ~/testdir>

Звісно, останні команди було введено лише для демонстрації того, що сценарій відсилає нормальне поштове повідомлення із заголовками «To:», «Subject:» та «From:»; ви можете прочитати цього листа будь-яким поштовим переглядачем.

Багато прикладів використання case можна знайти у каталозі стартових сценарїв. Сценарії завантаження використовують варіанти start та stop для запуску та зупинки системних процесів. Теоретичний приклад наведено у наступному параграфі.

Приклад сценарію завантаження

У сценаріях завантаження часто використовують оператори case для запуску, припинення та опитування системних служб. Нижче наведено виписування із сценарія, що запускає Anacron — демона, що періодично виконує команди.

case "$1" in
        start)
            start
            ;;
        stop)
            stop
            ;;
        status)
            status anacron
            ;;
        restart)
            stop
            start
            ;;
        condrestart)
            if test "x`pidof anacron`" != x; then
                stop
                start
            fi
            ;;
        *)
            echo $"Usage: $0 {start|stop|restart|condrestart|status}"
            exit 1
esac

Задачі, що виконуються у кожному випадку (такі, як запуск та припинення процесу), означені у функціях, частина з яких знаходиться у файлі /etc/rc.d/init.d/functions. За докладнішою інформацією зверніться до 11 розділу .

Підсумок

У цьому розділі ми навчилися створювати умови в наших сценаріях, що надає можливості виконувати різні набори команд залежно від успіху чи невдачі виконання будь-якої іншої команди. В цьому нам допомогає оператор if. Цей оператор дозволяє перевіряти арифметичні вирази, порівнювати рядки, перевіряти коди виходу, ввод користувача, а також наявність файлів, що потрібні вашому сценарію.

Проста перевірка if/then/fi часто уточнює команди у сценарію оболонки для того щоб попередити формування стандартного виводу, оскільки сценарій запросто може бути запущеним у фоні чи за допомогою демона cron. Більш складні умови можна обробляти за допомогою оператора case.

Якщо перевірка була успішною, сценарій може явно повернути нульовий код виходу, щоб проінформувати батьківський сценарій про успіх. У разі невдачі можна використовувати будь-які інші коди. В залежності від коду виходу батьківський сценарій може діяти по різному.

Вправи

Нижче є декілька вправ, що допоможуть вам розібратися з умовними операторами:

  1. Напишіть сценарій з використанням if/then/elif/else, що виводить інформацію про поточний місяць. Він повинен відображувати кількість днів у місяці, а також інформацію про високосні роки, якщо поточним місяцем є лютий.
  2. Зробіть те ж саме, але за допомогою case та з альтернативним використанням команди date.
  3. Змініть /etc/profile таким чином, щоб у разі входу в систему користувача root видавалося спеціальне повідомлення.
  4. Відредагуйте сценарій leaptest.sh таким чином, щоб він приймав один аргумент — рік. Перевірте, що сценарію передали саме один аргумент.
  5. Напишіть сценарій whichdaemon.sh, що перевіряє, чи запущені в системі демони httpd та init. Якщо так, сценарій повинен виводити повідомлення «На цьому комп'ютері працює веб-сервер». Використайте команду ps для перевірки процесів.
  6. Напишіть сценарій, що робить резервування вашого домашнього каталогу на видалений комп'ютер за допомогою команди scp. Сценарій повинен додавати записи до файлу протоколу, наприклад, ~/log/homebackup.log. Якщо у вас немає доступу до іншої машини, використовуйте localhost для перевірки сценарію. Це потребує два ключа SSH між обома хостами, або ж вам знадобиться вказувати пароль. Створення ключів SSH пояснюється у man ssh-keygen.

    Цей сценарій повинен використовувати tar cf для створення архіву та gzip чи bzip2 для стиснення .tar-файлу. Усі файли повинні бути заданими у змінних. Назву віддаленого комп'ютера та віддаленого каталогу теж потрібно задати у змінних. Це дозволить легко налаштовувати сценарій та поширювати його у майбутньому.

    Сценарій повинен перевіряти на існування попереднього архівного файлу. Якщо він існує, треба видалити його, щоб попередити вивід повідомлень про помилки.

    Сценарій також повинен перевіряти вільне місце на диску. Пам'ятайте, що вам потрібно розмістити на розділі дані користувача, дані у файлі .tar, а також дані у стиснутому архіві. Якщо місця недостатньо, треба видати помилку у файл протоколу та завершити сценарій.

    Сценарій повинен видалити стиснутий архів перед завершенням.