Цикли while і until: організація пошуку

У розділі 3 для виконання деякої кількості повторюваних програм застосовувався цикл for Зазвичай цикл for переглядає список імен файлів (наприклад, for i in * C) або всі аргументи програми оболонки (For i in $ *) Але цикли оболонки можуть застосовуватися не тільки для вирішення таких завдань, – подивіться на цикл for в програмі which

Існує три види циклів: for, while і until Безумовно, найбільш поширеним з них є for Він виконує набір команд – тіло циклу – один раз для кожного елемента з безлічі слів (частіше всього це імена файлів) Цикли while і until виконують команди тіла циклу на основі аналізу коду завершення команди У операторі while тіло циклу виконується до тих пір, поки команда-умова не поверне ненульовий код для оператора until – поки команда-умова не поверне нульовий код Цикли while і until ідентичні, якщо не вважати відмінностей в інтерпретації коду завершення команди

Базова форма кожного з описаних циклів виглядає наступним чином:

for  i in  список слів

do

done

тіло циклу, $i  встановлюється в наступний елемент списку

for  i    (Мається на увазі список всіх аргументів командного файлу, тобто $*)

do

done

тіло циклу, $i  встановлюється в наступний аргумент

while  команда

do

done

тіло циклу виконується, поки команда повертає true

until      команда

do

done

тіло циклу виконується, поки команда повертає false

Друга форма for, в якій під порожнім рядком мається на увазі $ *, являє собою зручну коротку запис для постійної роботи

В якості команди-умови, керуючої циклом while або until, може виступати будь-яка команда Наведемо тривіальний приклад – цикл while, що стежить за входом користувача (скажімо, Мері) в систе му:

while  sleep  60 do

done

who  | grep  mary

Команда sleep, що створює паузу довжиною 60 секунд, зазвичай виконується завжди (до тих пір, поки не буде перервана), отже, повертає «успіх», так що цикл разів на хвилину перевірятиме, зорі стровані Чи Мері

Недолік цієї версії полягає в тому, що якщо Мері вже зорі стровані, ви зможете дізнатися про це тільки через 60 секунд І якщо Мері продовжує працювати в системі, раз на хвилину надходитимуть повідомлення про це Можна вивернути цикл «навиворіт» і переписати його за допомогою оператора until, щоб отримувати інформацію один раз, без затримки – у разі, якщо Мері зараз у системі:

until  who  |  grep  mary do

done

sleep 60

Це більш цікаве умова Якщо Мері в системі, то who | grep mary виводить її дані в списку who і повертає «істину», тому що grep повертає код, який вказує, чи знайдено небудь, а кодом завершення конвеєра є код завершення його останнього елемента

Тепер завершимо цю команду, дамо їй назву і проінсталліруем її:

$ cat  watchfor

# Watchfor: стежить за входом користувача в систему PATH = / bin :/ usr / bin

case  $# in

0)    echo Usage:  watchfor  person  1&gt&amp2  exit 1 esac

until  who  |  egrep  &quot&quot do

done

sleep 60

$ cx  watchfor

$ watchfor  you

you       tty0      Oct      1 08:01       Працює

$ mv watchfor / usr / you / bin Інсталюємо її

$

Команда grep замінена на egrep, тому можна ввести

$ watchfor  joe|mary

щоб відстежувати відразу декількох користувачів

Більш складний приклад: будемо відстежувати вхід в систему і вихід з неї всіх користувачів і виводити звіт про «рух» користувачів – вийде щось на зразок розширеної команди who Базова структура дуже проста: раз на хвилину запускати who, порівнювати її вихідні дані з її ж даними хвилину тому і друкувати інформацію про будь відмінностях Вихідні дані who будуть зберігатися у файлі, розташованому в каталозі / tmp Щоб відрізняти наші файли від файлів, що належать іншим процесам, в імена файлів включена змінна оболонки $ $ (ідентифікатор процесу команди) це загальноприйнята угоду В імені тимчасового файлу зашифрована назва відповідної команди – це зручно для системного адміністратора Команди (у тому числі і ця версія watchwho) часто залишають непотрібні файли в / tmp, тому важливо мати можливість визначити, ка кая саме команда так чинить

$ cat  watchwho

# Watchwho: стежить за тим, хто входить в систему і виходить з неї

PATH=/bin:/usr/bin new=/tmp/wwho1$ old=/tmp/wwho2$

> $ Old # створити порожній файл

while: # вічний цикл do

who  &gt$new

diff $old  $new mv  $new $old sleep 60

done | awk /&gt/ { = &quotin:       " print }

/&lt/ { = &quotout:     " print }

Команда: вбудована в оболонку, єдине, що вона вміє робити – це оцінювати свої аргументи і повертати «істину» Замість неї можна було використовувати команду true, яка просто повертає код завершення «істина» (Існує й команда false) Але: більш ефективна, ніж true, так як вона не виконує команду з файлової системи

У висновку diff використані < і>, щоб розрізняти дані з двох файлів програма awk обробляє цю інформацію і повідомляє про зміни в більш доступному для розуміння форматі Зверніть вни мание на те, що весь цикл while зєднується з awk, утворюючи конвеєр (а можна було б запускати awk окремо, раз на хвилину) Для такої обробки не можна використовувати команду sed, оскільки її висновок завжди слід за рядком введення: завжди є рядок введення, яка обробляється, але не виводиться, так виникає непотрібна затримка

Файл old створюється порожнім, тому першим висновком команди watch-who є список користувачів, що знаходяться в системі зараз Якщо замінити команду, яка спочатку створює old, на who> $ old, то watchwho буде друкувати тільки відмінності вибір тут – справа смаку

Розглянемо іншу програму, реалізація якої вимагає застосування циклів: періодичний перегляд поштової скриньки Якщо є зміни, програма виводить повідомлення «Вам прийшла пошта» Така програма зовсім не зайва, вона являє собою гарну аль тернатіву вбудованому в оболонку механізму, котрі використовують змінну MAIL Представлена ​​реалізація використовує замість файлів змінні оболонки (просто для того, щоб показати, що таке теж можливо)

$ cat  checkmail

# Checkmail: стежить за збільшенням розміру поштової скриньки

PATH=/bin:/usr/bin

MAIL = / usr / spool / mail / `getname` # залежить від системи t = $ {1-60}

x=&quot`ls  –l  $MAIL`&quot while  :

do

y=&quot`ls  –l  $MAIL`&quot echo $x  $y

x=&quot$y&quot sleep $t

done | awk $ 4 < $ 12 {print "Вам прийшла пошта" } '

$

Знову ми вдалися до команди awk, на цей раз для того, щоб забезпечити виведення повідомлення тільки у разі збільшення поштової скриньки, а не просто при його зміні В іншому випадку повідомлення виводь-

лось би і після видалення повідомлення (Ця вада є у версії, вбудо енной в оболонку)

Проміжок часу зазвичай дорівнює 60 секундам, але можна задати інше значення, вказавши параметр у командному рядку:

$ checkmail  30

Мінлива оболонки t встановлюється в задане значення (якщо воно введене) або в 60, якщо значення не задано, за допомогою рядка

t=${1–60}

У ній використовується ще одна властивість оболонки

Позначення $ {var} еквівалентно $ var, воно зручно для того, щоб уникнути неприємностей з змінними всередині рядків, що містять букви або цифри:

$ var=hello

$ varx=goodbye

$ echo $var

hello

$ echo $varx

goodbye

$ echo ${var}x

hellox

$

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

$ echo ${var}

hello                                                           Все добре var  визначена

$ echo ${junk}

junk:  parameter not  set       Стандартне повідомлення (за замовчуванням)

$ echo ${junkerror}

junk:  error                                    Виведено задане повідомлення

$

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

Ще одна можлива форма даного позначення виглядає так: $ {var-thing}, цей вираз має значення $ var, якщо var визначена, і thing, якщо не визначена Вираз $ {var = thing} обчислюється аналогічно, але воно ще присвоює $ var значення thing:

$ echo ${junk-Hi there}

Hi there

$ echo ${junk}

junk:  parameter not  set             junk  не змінений

$ echo ${junk=Hi  there}

Hi there

$ echo ${junk}

Hi there                                              junk  встановлений вHi  there

$

Правила обчислення змінних наведено в табл 53

Таблиця 53 Обчислення змінних оболонки

Мінлива

Значення

$var

${var}

${var–thing}

${var=thing}

${varmessage}

${var+thing}

значення var якщо var не визначена, то нічого

аналогічно зручно використовувати, якщо за імям змінної слід буквено-цифровий вираз

значення var, якщо вона визначена в іншому випадку

thing $ Var не змінюється

значення var, якщо вона визначена в іншому випадку

thing, $ var встановлюється в thing

значення var, якщо вона визначена Інакше вивести message і вийти з оболонки Якщо повідомлення порожньо, вивести:

var: parameter  not  set

thing, якщо var визначена, інакше нічого

Повернемося до прикладу, з якого почалося обговорення таких виразів:

t=${1–60}

t встановлюється в $ 1, а якщо аргумент не заданий, то в 60

Вправа 59Подивіться на реалізацію команд true і false в каталозі / bin або / usr / bin (Як їх знайти) ~

Вправа 510Змініть команду watchfor так, щоб при завданні кількох аргументів вони сприймалися як різні користувачі (щоб не доводилося вводити joe | mary) ~

Вправа 511Напишіть версію watchwho, яка використовувала б comm, а не awk, для порівняння старих і нових даних Яку з версій ви віддаєте перевагу ~

Вправа 512Напишіть версію watchwho, яка зберігала б вихідні дані who не в файлах, а в змінних оболонки Яка версія вам більше подобається Яка працює швидше Чи слід командам watchwho і checkmail виконувати & автоматично ~

Вправа 513У чому відмінність команди оболонки: (яка нічого не робить) від символу коментаря # Чи справді потрібні обидва ~

Джерело: Керниган Б, Пайк Р, UNIX Програмне оточення – Пер з англ – СПб: Символ-Плюс, 2003 – 416 с, Мул

Схожі статті:


Сподобалася стаття? Ви можете залишити відгук або підписатися на RSS , щоб автоматично отримувати інформацію про нові статтях.

Коментарів поки що немає.

Ваш отзыв

Поділ на параграфи відбувається автоматично, адреса електронної пошти ніколи не буде опублікований, допустимий HTML: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>

*

*