Для виходу з циклу bash. BASH: опис циклів for, while, until та приклади використання

І ось настала черга п'ятого топіка циклу. У ньому я продовжу розглядати керуючі структури командного інтерпретатора bash. У попередньому пості було розібрано умовних операторів. Тепер настала черга таких невід'ємних мовних структур, як оператори циклу. Цикли, як і умови, є інструментальними засобами, які забезпечують управління порядком виконання команд.
Bash підтримує цикли типу for, while, until і select. Тепер перейдемо до детального розгляду кожного з них.

Оператор циклу for

Загальний синтаксис оператора:

for змінна
do
список команд
done

Цикл for bash значно відрізняється від циклу for в таких мовах програмування, як C або PHP. Тому, якщо ви програмуєте на C, вам потрібно буде звикнути до цих відмінностей, щоб не плутатися.
В результаті підстановки шаблону виходить список слів. При кожній ітерації змінна приймає кожне наступне значення цього списку і виконуються команди, що стоять між do і done. Ітерації припиняються через вичерпання слів у списку.
$ for day у Mon Tue Wed Thu Fri do echo “Сьогодні $day” done
Зарезервовані слова оператора for також можна писати в один рядок, як це було в попередньому пості для оператора if. Для цього потрібно ставити ";". Перепишемо попередній приклад з урахуванням даної можливості:
$ на день в Mon Tue Wed Thu Fri; do echo "Сьогодні $day"; done
Відсутність конструкції еквівалентного запису in [email protected]Про параметр [email protected]говорилося в.

Оператор циклу while

Загальний синтаксис оператора while:

while список1
do
список2
done

Спочатку виконується список1. Якщо він завершується успішно, тобто повертає нульовий код, керування переходить списку2. Ітерації продовжуються доти, доки результат виконання списку1 не стане ненульовим. Наприклад:
i = 10 while [$ i - gt 0]; do echo $i i=$(($i-1)) done; echo "end"

Оператор циклу until

Загальний синтаксис оператора until:

until список1
do
список2
done

Спочатку виконується список1. Якщо він завершується неуспішно, тобто з ненульовим кодом повернення управління переходить списку2. Ітерації продовжуються доти, доки результат виконання списку1 не стане нульовим. Наприклад:
i=10 until [$i -lt 0]; do echo $i i=$(($i-1)) done; echo "end"

Оператор циклу select

Загальний синтаксис оператора select:

select змінна
do
перелік
done

В результаті підстановки шаблону виходить список слів. До цих слів оператор додає порядкові номери та виводить весь набір до стандартного потоку помилок. Відсутність конструкції еквівалентного запису in [email protected]Після цього виводиться запрошення та зчитується рядок зі стандартного потоку введення. Якщо рядок містить номер, відповідний будь-якому слову зі списку, змінна отримує його як значення. Якщо відповідного слова не було знайдено, то змінною стає порожній рядок. Після цього виконується список команд, і ітерації продовжуються доти, доки у рядку введення не потрапить символ кінця файлу або доки у списку команд не зустрінеться break чи return.
Команди break і return служать управління ходом виконання циклу. Команда break перериває виконання циклу, в той час, як return повертає код результату (нульовий або ненульовий).
Оператор select корисний створення нумерованих меню. Наприклад, у каталозі ~/temp знаходиться 3 файли: proto.txt, file.txt і readme. Приклад фрагмента скрипта, що дозволяє швидко переглянути будь-який із них.
echo "Виберіть файл для перегляду:" select file in ~/temp/* Quit; do if [-f $file]; then cat $file; else break; fi done
Запустивши цей скрипт, ми побачимо на екрані:
Виберіть файл для перегляду:
1) /home/istergul/temp/file.txt
2) /home/istergul/temp/proto.txt
3) /home/istergul/temp/readme
4) Quit

У наступному топіці будуть розглянуті умовні підстановки параметрів. Чекаю на ваші коментарі.

На цій лекції ми продовжуємо знайомитись з bash. Ми розглядаємо ті елементи bash, які допоможуть нам розуміти скрипти операційної системи. Такими елементами безумовно є цикли та функції. Якщо хтось вивчав програмування, то труднощів із розумінням цих питань не виникне.

Цикл for

Цикл forв bashмає два види. Розглянемо спочатку класичний варіант for. Загальний вигляд наступний:

Між елементами forі inзадається змінна, яка по черзі набуває значення послідовності значень заданої між inі do. між doі doneзнаходяться команди які виконуються щоразу, коли змінна змінює своє значення. Цикл припиняє роботу, коли змінна прийме останнє значення з послідовності. Значення в послідовності задаються через пропуск.

А ось практичний приклад:

Послідовність значень можна задавати у різний спосіб. Очевидно — як у прикладі вище, чи з допомогою інших змінних, чи з допомогою спеціальних команд. Розглянемо деякі приклади. Так як значення задаються через пробіл, то як такі значення може бути будь-яка змінна, яка містить рядок з пробілами:

Результат буде таким самим, як і в першому прикладі.

Якщо необхідно задати послідовність чисел, можна скористатися командою seqта механізмом підстановки. Команда seqповертає на екран послідовність числових значень. Синтаксис простий і зрозумілий з прикладу нижче:

Результат:

Повернемося до другого виду for. Часто в скриптах можна зустріти так званий С-подібний варіант for, які використовуються для циклів на основі чисел. Розглянемо відразу приклад:

Цикл виконується поки що перевіряється у виразі умова вірно. Як тільки вираз повертає брехню, виконання циклу припиняється.

Практичний приклад:

#!/bin/bash
i=1
while [ $i -lt 7 ]
do
echo $i
let i=i+1
done

У нашому прикладі перевіряється, що змінна iменше (-lt), числа 7 і якщо це так, значення змінної виводиться на екран. Вираз let i=i+1, Збільшує змінну на одиницю, знову відбувається перевірка і т.д. let говорить інтерпретатору у тому, що аргументи слід розпізнавати як числові значення. Цей рядок можна було записати як let i++(C-подібний варіант). При збільшенні числа більш ніж одиницю можна записати так: let i+=2- в цьому випадку iбуде збільшуватися з кроком 2. Ще один варіант збільшення змінної це використання вбудованого калькулятора (працює лише з цілими числами). Доступ до калькулятора можна отримати через подвійні дужки: i=$(($i+1))або через квадратні: i=$[$i+1]Користуватися калькулятором можна і в командному рядку:

З циклами потрібно бути обережними, щоб не отримати варіант нескінченного циклу. До речі для налагодження bashскриптів можна змінити перший рядок на #!/bin/bash -xабо запускати скрипт командою bash -x:

[email protected]:~/linux$ bash -x ./testfor.sh
+ i=1
+ '[' 1 -gt 5 ']'
+ echo i=1
i=1
+ let i=i+1
+ '[' 2 -gt 5 ']'
+ echo i=2
i=2
+ let i=i+1
+ '[' 3 -gt 5 ']'
+ echo i=3
i=3
+ let i=i+1
+ '[' 4 -gt 5 ']'
+ echo i=4
i=4
+ let i=i+1
+ '[' 5 -gt 5 ']'
+ echo i=5
i=5
+ let i=i+1
+ '[' 6 -gt 5 ']'

Обов'язково потренуйтеся у написанні невеликих скриптів для закріплення розуміння роботи циклів bash.

Функції у bash

Функції застосовуються в bashдуже широко. Описуються функції двома способами: із ключовим словом functionі без нього.

Перший спосіб:

function ім'я_функції
{
тіло функції
}

Другий спосіб:

ім'я_функції ()
{
тіло функції
}

Викликається функція імені в будь-якому місці скрипта, але тільки після опису самої функції. Функції також можна передавати параметри, які задаються через пропуск після виклику (імені) функції. Розглянемо приклад скрипту bash:

#!/bin/bash
function primer
{
if [ $# -ne 0 ]
then
local a=1
echo «Кількість переданих параметрів – $#»
for i in [email protected]
do
echo «$ a-й параметр- $i»
let a++
done
return 0
else
echo «Параметри не передавалися»
return 1
fi
}
echo «Викликаємо функцію з параметрами:»
primer a b c
echo $?
echo «Викликаємо функцію без параметрів:»
primer
echo $?

У даному прикладізадана функція з ім'ям primer. Виклик функції з параметрами: primer a b cі без параметрів: primer. У тілі функції всі конструкції вам повинні бути знайомі, за винятком $# , $iі [email protected] .$# - Повертає кількість параметрів переданих функції. У нашому прикладі це буде число 3 .[email protected] повертає всі параметри одним рядком. У прикладі це буде a b c. А через $1 , $2 , $3 і т.д. можна звертатися до кожного параметра персонально. $? - Містить код виконання останньої команди. У прикладі код виконання функції.

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

Все, що стосується передачі параметрів у функцію, працює так само і для скрипту. Скрипту точно можна передавати параметри і точно також маніпулювати ними за допомогою $#, [email protected], $N. З цієї ж категорії і варіант $0 - який повертає ім'я команди, що запустила скрипт. Якщо скрипт запускався за командою ./script.sh, то echo $0 поверне значення ./script.sh, а якщо за командою /home/igor/linux/script.sh, то буде повернено значення /home/igor/linux/script.sh.

Одне з основних правил системного адміністрування можна висловити так: якщо вам потрібно часто робити те саме, напишіть сценарій, і нехай він робить цю роботу за вас. Якщо вам необхідно виконувати якусь дію всередині сценарію кілька разів, вам варто скористатися циклами. У GNU Bashви можете створювати цикли за допомогою конструкцій for, whileі until.

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

Цикл forпризначений для повторення дій до тих пір, поки вони не будуть виконані. Уявіть, наприклад, що у вас є каталог із зображеннями, і вам необхідно перетворити їх з одного формату на інший. Ви можете використовувати цикл forспільно з програмою convertз пакета ImageMagick(або будь-якою іншою програмою), наприклад, для того, щоб перетворити зображення з формату JPEG на PNG. Або, наприклад, вам може знадобитися перетворити безліч звукових файлів з MP3в OGG Vorbis.

Цикл whileвикористовується для повторення дій Бувайвиконується (є істинним) якась умова. Цикл untilпрацює дещо інакше: він виконує дію доти, Доки не виконається умова. Так, наприклад, ви можете лічильник і виконувати дію доти, Доки його значення не досягне 10. Розглянемо це більш докладно на прикладах.

Почнемо з циклу for. Його формат такий:

For i in $(command); do command $i; done

Якщо ви використовуєте цикл forу скрипті, краще відформатувати його так:

#!/bin/bash for i in $(command); do command $i done

Так, наприклад, якщо вам потрібно зробити резервні копіївсіх HTML-файлів, що знаходяться в каталозі, ви можете використовувати таку команду:

For i in $(ls *html); do cp $i $i.bak; done

Тут створюється локальна змінна $i, виконується команда ls *html, результати виконання якої і будуть даними, що ініціалізують значення змінної $iпри кожній ітерації циклу (у нашому прикладі це буде список файлів, який повертає команда ls, по одному за кожну ітерацію. Далі виконується команда cp, якою серед параметрів передається змінна $i.

Хтось може запитати, чи обов'язково використовувати букву "i"як ім'я змінної? Ні. Ви можете використовувати будь-яке коректне для Bashім'я змінної. Звичайно ж, у сценаріях краще використовувати осмисленіші імена змінних, начебто $inputабо $html.

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

while та until

Розглянемо тепер конструкції whileі until. Також ми трохи скористаємося умовними виразами bash. У нашому прикладі ми будемо використовувати їх для того, щоб визначати, наприклад, чи є змінною значення більшим або меншим, ніж число X; чи існує файл і чи він каталогом. Ви також можете використовувати умовні вирази для визначення, наприклад доступності файлу для читання або присутності в його правах доступу GID-біта.

Давайте спробуємо зробити щось просте, наприклад, створимо кілька порожніх файлів. У житті це навряд чи стане вам у пригоді, але як приклад — саме воно.

#!/bin/bash i=0 while [ $i -lt 22 ] do touch $i i=$[$i+1] done

Цей скрипт створить 22 файли з іменами від 0 до 21. Цикл буде працювати доти, Бувайзначення змінної $iменше ( -lt) 22.

Тепер давайте позбудемося створених файлів за допомогою циклу until:

#!/bin/bash i=0 until [ $i -eq 22 ] do rm $i i=$[$i+1] done

Тут ми замінили whileна until, а в умовному вираженні замінили «менше» (-lt) на «рівно» (-eq). Таким чином, наш скрипт буде працювати до тих пір, поки значення $iне досягне 22. І замість touchми використали rm, щоб видаляти файли, а не створювати їх. Просто, чи не так?

Цикли - це вкрай зручна штука при написанні будь-яких програм або скриптів, скоріше навіть необхідна. Вони дозволяють нам виконувати певну ділянку коду задану кількість разів. Природно, у bash є кілька видів циклів. Ми опишемо цикли for in, for, while, until. Хоча for in і for вважаються різним синтаксисом одного оператора, на мій погляд вони відрізняються один від одного більше, ніж while від until.

Цикл із лічильником for in:

Цикл for inце цикл із лічильником. Блок коду що знаходиться в тілі циклу повторюється стільки разів, скільки значень міститься в списку оператора for in при тому, при кожному повторі змінна лічильника (тут вона названа var, але можна називати її як завгодно) має значення наступного елемента списку.
Якщо ключове слово do знаходиться в одному рядку зі словом for, після списку аргументів (перед do) необхідно ставити крапку з комою.
Кожен із елементів<список>може містити кілька аргументів. Це корисно при обробці груп параметрів. У цьому випадку для примусового розбору кожного з аргументів у<списке>необхідно використовувати інструкцію set
Як список, в циклі for, можна використовувати змінну.
У<списке>циклу for можуть бути використані імена файлів, які можуть містити символи-шаблони. Це може стати в нагоді при роботі з великою кількістю файлів.
Якщо<список>в циклі for не заданий, то як воно використовується змінна [email protected]- Перелік аргументів командного рядка.
При створенні списку аргументів у циклі for можна використовувати підстановку команд.
Виведення циклу може бути перенаправлений зі stdout у файл або кудись ще (докладніше це можна дізнатися розбираючи перенаправлення введення-виведення).

Синтаксис:
for var in<список>
do
<выполняемые команды>
done

Приклад:
for names in name1 name2 name3 name4
do
echo $names
done

Оператор циклу forмає ще один спосіб запису - дуже схожий на синтаксис оператора for в мові C. У цьому випадку при ініціалізації лічильників задаються початкові значення змінних або однієї змінної і після кожного циклу проходу перевіряється умова, якщо перевірка повертає істину, то починається наступний прохід циклу. У блоці<приращение счётчиков>Значення наших змінних лічильників обов'язково повинні змінюватися (не обов'язково у велику сторону) так щоб під час перевірки умови рано чи пізно ми отримали значення лож, інакше цикл ніколи не закінчиться. Дуже зручний і головне звичний варіант, якщо якусь операцію потрібно повторити задану кількість разів.

З подібним синтаксисом:
for ((<инициализация счётчиков>; <проверка условия>; <приращение счётчиков>))
do
<выполняемые команды>
done

Приклад:
for ((var=1; var<= LIMIT ; var++))
do
echo $var
done

Цикл while:

Це досить проста конструкція, яка перевіряє умову, що стоїть за оператором. whileі у разі істинності цієї умови виконує блок команд, що знаходиться між словами do і done і потім знову переходить до перевірки умови. Якщо перевірка поверне лож, то цикл закінчується і починаю виконуються команди наступні за done. Потрібно обов'язково стежити за тим, щоб<проверка условия>залежала від коду виконується в циклі інакше, якщо результат перевірки не змінюється ви отримаєте нескінченний цикл.
Стандартний пристрій введення для циклу while можна перенаправити на файл за допомогою команди перенаправлення< в конце цикла.

Синтаксис:
while<Проверка условия>
do
<Блок команд, обязательно меняющий переменные влияющие на проверку условия>
done

Приклад:
while [ $ var0 -eq 100 ]
do
echo $var
var++
done

Оператор whileможе мати кілька умов. Але лише останнє з них визначає можливість продовження циклу. У цьому випадку синтаксис оператора циклу відрізнятиметься від звичайного.
Синтаксис(Ще раз повторюся, що на виконання циклу впливає лише остання умова) :
while
<условие1>
<условие2>

<условиеN>
do
<выполняемые команды - тело цикла>
done

Цикл until:

Оператор untilдуже схожий на while, він теж обчислює умову, але виконує тіло циклу якщо результатом обчислення буде лож. Може здатися незвичним, але until обчислює перед першим проходом циклу, як і while, а не після нього. Як і у разі циклів for/in, при розміщенні ключового слова do в одному рядку з оголошенням циклу, необхідно вставляти символ ";" перед do.
Як і в попередньому випадку важливо пам'ятати, що умова повинна залежати від операцій у тілі циклу, інакше наш скрипт ніколи не завершиться.

Синтаксис:
until<Проверка условия>
do
<Блок команд, обязательно меняющий переменные влияющие на проверку условия>
done

Приклад:
until [ $var0 -gt 100] # Перевірка умови проводиться на початку ітерації.
do
echo $var
var--
done

Напевно, поки вистачить. :)

  • назад
  • Вперед

Нові статті:

  • Не вмикається мережне виявлення у Windows 7/8/2008/2012
  • Помилка: Це застосування неможливе для запуску тому, що він не може почати або завантажити платформу plug-in Qt «windows».
  • Налаштування автоматичного перезапуску робочих процесів rphost.exe сервера 1С 8.3
  • Як зменшити розмір лога транзакцій (.ldf) у MS SQL 2008/20012

    MS SQL як будь-яка порядна СУБД промислового призначення разом з базою даних веде транзакційні логи, які дозволяють відкочувати стан...

5

Скрипт закодований небезпечним чином.

По-перше, я припускаю, що ви використовуєте оболонку Bash, тому що ви відзначили її "/bash" та "/for".

У моїй відповіді я процитую це чудове Bash guide, що, ймовірно, є найкращим джерелом для вивчення Bash.

1) Ніколи не використовувати Command Substitution , абороду, без лапок. Тут існує велика проблема: використання розширення, що не котирується, для поділу висновку на аргументи.

Конкретно кажучи, це $(find$ DIRWORK -type d -name work) і $(find$ DIR -type f) зазнає Word Splitting , таким чином, якщо find знаходить файл із пробілами у його імені, тобто "ім'я файлу", слово Розщеплення результат Bash буде проходити 2 аргумент для for команди ітерації по, тобто один для файлу і один для імені. У цьому випадку ви хочете сподіватися, що ви отримаєте файл: немає такого файлу або каталогу і ім'я: немає такого файлу або каталогу, а не потенційно завдавати їм шкоди, якщо вони дійсно існують.

2) За згодою змінні середовища (PATH, EDITOR, SHELL, ...) та внутрішні змінні оболонки (BASH_VERSION, RANDOM, ...) повністю капіталізуються. Всі інші імена змінних мають бути малими. Оскільки імена змінних чутливі до регістру, ця угода дозволяє уникнути випадкового перевизначення екологічних та внутрішніх змінних.

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

My_home="/root/mydir" my_dir="$my_home/var" dir_work="$ my_home/Local" while IFS= read -r -d "" f; do # I"m guessing that you also want to ignore stderr; # this is where the 2>&1 came from. if lsof -n " ​​$f" | grep "" > /dev/null 2> then echo "hey, I "m safer now!" fi done< <(find "$ dir_work" -type f -print0) while IFS= read -r -d "" f; do echo "2" done < <(find "$dir_work" -type d -name "work" -print0)

Як ви можете бачити, змінна IFS встановлюється рівним порожня, таким чином запобігаючи read від обрізки переднього та заднього простору з рядка. команда read використовує порожній рядок (-d "") в якості роздільника, щоб читати до він досягає a \ 0. find повинен бути m відповідно, тому він використовує опцію -print0 , щоб розмежувати свої дані за допомогою \ 0 замість нового рядка, що що дивно і зловмисно, може бути частиною імені файлу. Розбиття такого файлу на дві частини порушить наш код.

Попередня відповідь, в якій зазначено, що find ... | while read name; do ...; done слід використовувати для зчитування find s вихід може бути поганим. Цикл while виконується у новій підболочці зі своєю копією змінних, скопійованою з батька. Потім ця копія використовується всім, що вам подобається. Коли цикл коли закінчено, копія підболочки буде відкинута, а вихідні змінні батька не будуть змінені.

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

0

"Ніколи не використовуйте Command Substitution, будь-якого виду, без лапок". Це просто nitpicking, але можна використовувати підстановку команд без лапок, коли ви встановлюєте змінну: "something = $ (basename" filename with spaces ")". - Smith John 22 квіт. 13 2013-04-22 21:43:10

2

For i in $(find$ DIRWORK -type d -name work); do echo "2" done

буде першим виконати цю лінію

Find $DIRWORK -type d -name work

чекати, поки find не завершить виконання, а потім взяти вихідний і покласти його назад у петлю for

For i in the output of find; do echo "2" done

Тільки тоді цикл for розпочне виконання.

Тому якщо find займає багато часу, щоб закінчити цикл for , необхідно почекати багато часу, перш ніж він зможе почати.

Спробуйте тимчасові команди find в інтерактивному режимі

$time find $DIRWORK -type d -name work

та подивитися, як довго це бере.

Також зверніть увагу: ви не повинні використовувати цикл для перебору імен файлів. Використовуйте while петлю з read , як це:

Find$ DIRWORK -type d -name work | while read name; do echo "2" done

Бонус: він виконує цикл, while паралельно з find . Це означає, що цикл while виконає одну ітерацію, коли find роздрукує один рядок. Для завершення виконання не потрібно чекати find.

mob_info