Bash-скрипти, частина 2 цикли
Минулого разу ми розповіли про основи програмування для bash. Навіть те, що вже розібрано, дозволяє всім бажаючим приступити до автоматизації роботи в Linux. У цьому матеріалі продовжимо розповідь про bash-скрипти, поговоримо про керуючі конструкції, які дозволяють виконувати дії, що повторюються. Мова йде про цикли for і while, про методи роботи з ними та про практичні приклади їх застосування.

Увага:у пості захована вигода!
Оболонка bash підтримує цикли for, які дозволяють організовувати перебір послідовностей значень. Ось яка базова структура таких циклів:
У кожній ітерації циклу змінну var буде записуватися наступне значення зі списку list . У першому проході циклу таким чином буде задіяно перше значення зі списку. У другому - друге, і так далі - до тих пір, поки цикл не дійде до останнього елемента.
Перебір простих значень
Мабуть, найпростіший приклад циклу for у bash-скриптах – це перебір списку простих значень:
Нижче наведено результати роботи цього скрипту. Добре видно, що змінну $var послідовно потрапляють елементи зі списку. Відбувається так доти, доки цикл не дійде до останнього з них.

Змінна $var зберігає значення при виході з циклу, її вміст можна змінювати, загалом, працювати з нею можна як з будь-якою іншою змінною.
Перебір складних значень
У списку, використаному при ініціалізації циклу for , можуть міститися не тільки прості рядки, що складаються з одного слова, але й цілі фрази, в які входять кілька слів та розділових знаків. Наприклад, все це може виглядати так:
Ось що вийде після того, як цей цикл пройде за списком. Як бачите, результат цілком очікуваний.
Перебір складних значеньTNW-CUS-FMP — промо-код на 10% знижку на наші послуги, доступний для активації протягом 7 днів"
Ініціалізація циклу списком, отриманим із результатів роботи команди
Ще один спосіб ініціалізації циклу for полягає у передачі йому списку, який є результатом роботи команди. Тут використовується підстановка команд для їх виконання та отримання результатів їхньої роботи.
У цьому прикладі задіяна команда cat, яка читає вміст файлу. Отриманий список значень передається до циклу та виводиться на екран. Зверніть увагу на те, що файл, до якого ми звертаємося, містить список слів, розділених знаками перекладу рядка, пробіли при цьому не використовуються.
Цикл, який перебирає вміст файлу
Тут треба врахувати, що такий підхід, якщо очікується рядкова обробка даних, не спрацює для файлу складнішої структури, у рядках якого може бути по кілька слів, розділених пробілами. Цикл оброблятиме окремі слова, а не рядки.
Що якщо це зовсім не те, що потрібно?
Розділювачі полів
Причина вищеописаної особливості полягає у спеціальній змінній оточенні, яка називається IFS (Internal Field Separator) і дозволяє вказувати роздільники полів. За замовчуванням оболонка bash вважає роздільниками полів такі символи:
- Пробіл
- Знак табуляції
- Знак перекладу рядка
Якщо bash зустрічає в даних будь-який із цих символів, він вважає, що перед ним наступне самостійне значення списку.
Для того щоб вирішити проблему, можнатимчасово змінити змінну середовища IFS. Ось як це зробити в bash-скрипті, якщо виходити з припущення, що як роздільник полів потрібен тільки переклад рядка:
Після додавання цієї команди до bash-скрипту, він буде працювати як слід, ігноруючи прогалини та знаки табуляції, вважаючи роздільниками полів лише символи перекладу рядка.
Якщо цей скрипт запустити, він виведе саме те, що від нього вимагається, даючи, в кожній ітерації циклу, доступ до чергового рядка, записаної у файл.

Розділювачами можуть бути інші символи. Наприклад, ми виводили на екран вміст файлу /etc/passwd . Дані про користувачів у рядках розділені за допомогою двокрапок. Якщо в циклі потрібно обробляти такі рядки, IFS можна налаштувати так:
Обхід файлів, що містяться в директорії
Один із найпоширеніших варіантів використання циклів for у bash-скриптах полягає в обході файлів, що знаходяться в якійсь директорії, і в обробці цих файлів.
Наприклад, ось як можна вивести список файлів та папок:
Якщо ви розібралися з попереднім матеріалом із цієї серії статей, вам повинен бути зрозумілий пристрій конструкції if-then , а також те, як відрізнити файл від папки. Якщо вам складно зрозуміти наведений вище код, перечитайте цей матеріал.
Ось що виведе скрипт.

При перевірці умови в операторі if ми укладаємо ім'я змінної в лапки. Зроблено це тому, що ім'я файлу або папки може містити пробіли.
Цикли for у стилі C
Якщо ви знайомі з мовою програмування C, синтаксис опису bash-циклів for може здатися вам дивним, оскільки звикли ви, очевидно, до такого описуциклів:
У bash-скриптах можна використовувати цикли for, опис яких виглядає дуже схожим на цикли в стилі C, щоправда, без деяких відмінностей тут не обійшлося. Схема циклу при такому підході виглядає так:
На bash це можна написати так:
А ось робочий приклад:
Цей код виведе список чисел від 1 до 10.

Цикл while
Конструкція for – не єдиний спосіб організації циклів у bash-скриптах. Тут можна користуватися і циклами while. У такому циклі можна задати команду перевірки певної умови і виконувати тіло циклу до тих пір, поки умова, що перевіряється, повертає нуль, або сигнал успішного завершення якоїсь операції. Коли умова циклу поверне ненульове значення, що означає помилку, цикл зупиниться.
Ось схема організації циклів while while команда перевірки умови do інші команди done
Погляньмо на приклад скрипту з таким циклом:
На вході в цикл перевіряється, чи більша за нуль змінна $var1 . Якщо це так, виконується тіло циклу, в якому значення змінної віднімається одиниця. Так відбувається в кожній ітерації, при цьому ми виводимо консоль значення змінної до його модифікації. Як тільки $var1 набере значення 0, цикл припиняється.

Якщо не модифікувати змінну $var1 , це призведе до попадання скрипта в безкінечний цикл.
Вкладені цикли
У тілі циклу можна використовувати будь-які команди, у тому числі запускати інші цикли. Такі конструкції називають вкладеними циклами:
Нижче показано, що виведе цей скрипт. Як видно, спочатку виконується перша ітерація зовнішнього циклу, потім три ітерації внутрішнього, після його завершення знову в справу вступаєзовнішній цикл, потім знову – внутрішній.

Обробка вмісту файлу
Найчастіше вкладені цикли використовують із обробки файлів. Так, зовнішній цикл займається перебором рядків файлу, а внутрішній працює з кожним рядком. Ось, наприклад, як виглядає обробка файлу /etc/passwd :
У цьому скрипті два цикли. Перший проходить рядками, використовуючи як роздільник знак перекладу рядка. Внутрішній зайнятий розбором рядків, поля яких розділені двокрапками.

Такий підхід можна використовувати при обробці файлів формату CSV, або будь-яких подібних файлів, записуючи, при необхідності, в змінну оточення IFS символ-розділювач.
Управління циклами
Можливо, після входу в цикл, потрібно буде зупинити його при досягненні змінної циклу певного значення, яке не відповідає заданій умові закінчення циклу. Чи потрібно буде в такій ситуації чекати нормального завершення циклу? Ні, звичайно, і в подібних випадках стануть у нагоді наступні дві команди:
Команда break
Ця команда дозволяє перервати виконання циклу. Її можна використовувати і для циклів for, і для циклів while:
Такий цикл, у звичайних умовах, пройде по всьому списку значень зі списку. Однак, у нашому випадку, його виконання буде перервано, коли змінна $var1 дорівнюватиме 5.
Достроковий вихід із циклу for
Ось те ж саме, але вже для циклу while :
Команда break , виконана, коли значення $var1 дорівнюватиме 5, перериває цикл. У консоль виведеться те саме, що й у попередньому прикладі.
Команда continue
Коли ця команда зустрічається в тілі циклу, поточна ітерація завершується достроково.і починається наступна, у своїй виходу з циклу немає. Подивимося на команду continue у циклі for :
Коли умова всередині циклу виконується, тобто коли $var1 більше 5 і менше 10, оболонка виконує команду continue . Це призводить до пропуску команд, що залишилися в тілі, і переходу до наступної ітерації.

Обробка виводу, що виконується у циклі
Дані, що виводяться в циклі, можна обробити або перенаправивши висновок, або передавши їх у конвеєр. Це робиться за допомогою додавання команд обробки виводу після інструкції done .
Наприклад, замість того, щоб показувати на екрані те, що виводиться в циклі, можна записати все це у файл або передати ще кудись:
Оболонка створить файл myfile.txt і перенаправить у файл висновок конструкції for . Відкриємо файл і переконаємося, що він містить саме те, що очікується.
Перенаправлення виведення циклу у файл
Приклад: пошук файлів, що виконуються.
Давайте скористаємося тим, що ми вже розібрали, і напишемо щось корисне. Наприклад, якщо потрібно з'ясувати, які саме файли, що виконуються, доступні в системі, можна просканувати всі папки, записані в змінну оточення PATH . Весь арсенал засобів, який для цього потрібен, у нас вже є, треба лише зібрати все це докупи:
Такий ось скрипт, невеликий і нескладний, дозволив отримати список файлів, що виконуються, що зберігаються в папках з PATH .

Сьогодні ми поговорили про цикли for і while у bash-скриптах, про те, як їх запускати, як ними керувати. Тепер ви вмієте обробляти в циклах рядки з різними роздільниками, знаєте, як перенаправляти дані, виведені вциклах, в файли, як переглядати та аналізувати вміст директорій.
Якщо припустити, що ви розробник bash-скриптів, який знає про них тільки те, що викладено в першій частині цього циклу статей, і в цій, другій, то ви вже цілком можете написати щось корисне. Попереду - третина, розібравшись з якою, ви дізнаєтеся, як передавати bash-скриптам параметри та ключі командного рядка, і що з цим усім робити.