BASH: опис циклів for, while, until та приклади використання. Нескінченний цикл while у BASH-скрипті Цикли WHILE та UNTIL

💖 Подобається?Поділися з друзями посиланням

Автор: Paul Cobbaut
Дата публікації: 16 жовтня 2014 р.
Переклад: А.Панін
Дата перекладу: 21 грудня 2014 р.

Розділ 22. Цикли у сценаріях

Команда test

Команда test дозволяє встановити, чи є якийсь вираз істинним чи хибним. Давайте почнемо з перевірки, чи більше цілочинне значення 10 цілочисельного значення 55 $ test 10 -gt 55 ; echo $? 1 $

Команда test повертає значення 1, якщо вираз є хибним. І, як ви побачите в наступному прикладі, команда test повертатиме значення 0, якщо вираз буде істинним. $ test 56 -gt 55; echo $? 0 $

Якщо вам зручніше працювати з рядками true (істина) і false (брехня), ви можете використовувати команду test таким чином, як показано нижче. $ test 56 -gt 55 && echo true || echo false true $ test 6 -gt 55 && echo true || echo false false

Команда test також може замінюватись квадратними дужкамитому команди з прикладу нижче повністю аналогічні командам з прикладу вище. $ [ 56 -gt 55 ] && echo true || echo false true $ [ 6 -gt 55 ] && echo true || echo false false

Нижче наведено приклади реалізації деяких перевірок. Зверніться до сторінки посібника man test для ознайомлення з додатковими можливостямиреалізації різноманітних перевірок. [-d foo] Чи існує директорія foo? [-e bar] Чи існує файл bar? [ "/etc" = $PWD ] Чи еквівалентний рядок /etc значення змінної $PWD ? [ $1 != "secret" ] Чи відрізняється значення першого параметра сценарію від рядка secret ? [ 55 -lt $bar ] Чи менше цілочислове значення 55 значення змінної $bar ? [ $foo -ge 1000 ] Чи є значення змінної $foo більшим або рівним цілісному значенню 1000 ? ["abc"< $bar ] Будет ли строка abc расположена выше значения переменной $bar в списке после сортировки? [ -f foo ] Является ли foo обычным файлом? [ -r bar ] Является ли bar файлом, що читається? [ foo -nt bar ] Чи новий файл foo файлу bar ? [ -o nounset ] Чи активовано командну оболонку nounset ?

Оператори перевірок можуть комбінуватись з операторами, що відповідають логічним операціям"І" та "АБО". paul@RHEL4b:~$ [ 66 -gt 55 -a 66 -lt 500 ] && echo true || echo false true paul@RHEL4b:~$ [ 66 -gt 55 -a 660 -lt 500 ] && echo true || echo false false paul@RHEL4b:~$ [ 66 -gt 55 -o 660 -lt 500 ] && echo true || echo false true

Умовний перехід if then else

Конструкція if then else призначена для вибору варіанта коду. У тому випадку, якщо певна умова виконується, буде виконуватися будь-який код, інакше буде виконуватись якийсь інший код. У прикладі нижче здійснюється перевірка існування файлу, після чого, якщо припущення про існування файлу підтверджується, здійснюється висновок відповідного повідомлення. #!/bin/bash if [ -f isit.txt ] then echo файл isit.txt існує! else echo файл isit.txt не знайдено! fi

Якщо ми збережемо цей код сценарію у файлі з ім'ям "choice", він зможе бути виконаний аналогічним чином. $./choice файл isit.txt не знайдено! $ touch isit.txt $./choice файл isit.txt існує! $

Умовний перехід if then elif

Ви можете розмістити новий оператор умовного переходу if всередині блоку else, скориставшись оператором elif. Нижче наведено простий приклад такого запису. #!/bin/bash count=42 if [ $count -eq 42 ] then echo "42 є коректним значенням." elif [ $count -gt 42 ] then echo "Занадто багато." else echo "Не достатньо." fi

Цикл for

У прикладі нижче представлений синтаксис класичного циклу for командної оболонці bash. for i in 1 2 4 do echo $i done

Приклад використання циклу for , скомбінованого з викликом командної оболонки, що вбудовується. #!/bin/ksh for counter in `seq 1 20` do echo відлік від 1 до 20, поточне значення $counter sleep 1 done

Сценарій, повністю аналогічний представленому вище, може бути створений і без залучення вбудованої командної оболонки шляхом використання реалізованого в рамках командної оболонки bash оголошення діапазону значень (від значення до значення). #!/bin/bash for counter in (1..20) do echo відлік від 1 до 20, поточне значення $counter sleep 1 done

У цьому циклі for використовується механізм пошуку файлів за шаблоном (реалізований у рамках механізму розкриття команд). У разі розміщення наведеної інструкції безпосередньо в командному рядку, вона функціонуватиме аналогічно. kahlan@solexp11$ ls count.ksh go.ksh kahlan@solexp11$ for file in *.ksh ; do cp $file $file.backup; done kahlan@solexp11$ count.ksh count.ksh.backup go.ksh go.ksh.backup

Цикл while

Нижче наведено простий приклад використання циклу while. i=100; while [$ i-ge 0]; do echo Зворотний відлік від 100 до 0, поточне значення $i; let i--; done

Нескінченні цикли можуть реалізовуватися за допомогою оголошень while true або while: де символ: є еквівалентом відсутньої операції в командних оболонках Korn shell і bash . #!/bin/ksh # нескінченний цикл while: do echo hello sleep 1 done

Цикл until

Нижче наведено простий приклад використання циклу until. let i = 100; until [$i-le 0]; do echo Зворотний відлік від 100 до 1, поточне значення $i; let i--; done

Практичне завдання: перевірки та цикли у сценаріях

3. Розробте сценарій, який використовуватиме цикл while для відліку від 3 до 7.

4. Розробте сценарій, який використовуватиме цикл until для зворотного відліку від 8 до 4.

5. Розробіть сценарій, який буде здійснювати підрахунок файлів з розширенням.txt у поточній директорії.

6. Використовуйте оператор if у створеному сценарії для нього коректної роботиу разі відсутності файлів з розширенням.txt у поточній директорії.

Коректна процедура виконання практичного завдання: перевірки та цикли у сценаріях

1. Розробіть сценарій, який використовуватиме цикл для відліку від 3 до 7.

#!/bin/bash for i in 3 4 5 6 7 do echo Відлік від 3 до 7, поточне значення $i done

2. Розробте сценарій, який використовуватиме цикл для відліку від 1 до 17000.

Оболонка bash підтримує цикли for, які дозволяють організовувати перебір послідовностей значень. Ось яка базова структура таких циклів:

For var in list do команди done
У кожній ітерації циклу змінну var буде записуватися наступне значення з списку list. У першому проході циклу таким чином буде задіяно перше значення зі списку. У другому - друге, і так далі - доти, доки цикл не дійде до останнього елемента.

Перебір простих значень

Мабуть, найпростіший приклад циклу for у bash-скриптах - це перебір списку простих значень:

#!/bin/bash for var у першій другій половині тридцяти п'ятої до echo $var item done
Нижче наведено результати роботи цього скрипту. Добре видно, що змінну $var послідовно потрапляють елементи зі списку. Відбувається так доти, доки цикл не дійде до останнього з них.


Простий цикл for

Змінна $var зберігає значення при виході з циклу, її вміст можна змінювати, загалом, працювати з нею можна як з будь-якою іншою змінною.

Перебір складних значень

У списку, використаному при ініціалізації циклу for , можуть міститися не тільки прості рядки, що складаються з одного слова, але й цілі фрази, в які входять кілька слів та розділових знаків. Наприклад, все це може виглядати так:

#!/bin/bash for var у першому "the second" "the third" "I'll do it" do echo "This is: $var" done
Ось що вийде після того, як цей цикл пройде за списком. Як бачите, результат цілком очікуваний.


Перебір складних значень
TNW-CUS-FMP - промо-код на 10% знижку на наші послуги, доступний для активації протягом 7 днів"

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

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

#!/bin/bash file="myfile" for var in $(cat $file) do echo "$var" done
У цьому прикладі задіяна команда cat, яка читає вміст файлу. Отриманий список значень передається до циклу та виводиться на екран. Зверніть увагу на те, що файл, до якого ми звертаємося, містить список слів, розділених знаками перекладу рядка, пробіли при цьому не використовуються.


Цикл, який перебирає вміст файлу

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

Що якщо це зовсім не те, що потрібно?

Розділювачі полів

Причина вищеописаної особливості полягає у спеціальній змінної оточення, Яка називається IFS (Internal Field Separator) і дозволяє вказувати роздільники полів. За замовчуванням оболонка bash вважає роздільниками полів такі символи:
  • Пробіл
  • Знак табуляції
  • Знак перекладу рядка
Якщо bash зустрічає в даних будь-який з цих символів, він вважає, що перед ним наступне самостійне значення списку.

Щоб вирішити цю проблему, можна тимчасово змінити змінну середовища IFS . Ось як це зробити в bash-скрипті, якщо виходити з припущення, що як роздільник полів потрібен тільки переклад рядка:

IFS=$"\n"
Після додавання цієї команди до bash-скрипту, він буде працювати як слід, ігноруючи прогалини та знаки табуляції, вважаючи роздільниками полів лише символи перекладу рядка.

#!/bin/bash file="/etc/passwd" IFS=$"\n" for var in $(cat $file) do echo " $var" done
Якщо цей скрипт запустити, він виведе саме те, що від нього вимагається, даючи, в кожній ітерації циклу, доступ до чергового рядка, записаної у файл.


Порядковий обхід вмісту файлу в циклі for

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

Обхід файлів, що містяться в директорії

Один із найпоширеніших варіантів використання циклів for у bash-скриптах полягає в обході файлів, що знаходяться в якійсь директорії, і в обробці цих файлів.

Наприклад, ось як можна вивести список файлів та папок:

#!/bin/bash для файлу в /home/likegeeks/* do if [ -d "$file" ] then echo "$file є directory" elif [-f "$file" ] then echo "$file is a file" fi done
Якщо ви розібралися з попереднім матеріалом із цієї серії статей, вам повинен бути зрозумілий пристрій конструкції if-then , а також те, як відрізнити файл від папки. Якщо вам складно зрозуміти наведений вище код, перечитайте цей матеріал.

Ось що виведе скрипт.


Виведення вмісту папки

Зверніть увагу на те, як ми ініціалізуємо цикл, а саме - на знак підстановки «*» в кінці адреси папки. Цей символ можна сприймати як шаблон, що означає: "всі файли з будь-якими іменами". він дозволяє організувати автоматичне встановлення імен файлів, які відповідають шаблону.

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

Цикли for у стилі C

Якщо ви знайомі з мовою програмування C, синтаксис опису bash-циклів for може здатися вам дивним, оскільки звикли ви, очевидно, до такого опису циклів:

For (i = 0; i< 10; i++) { printf("number is %d\n", i); }
У bash-скриптах можна використовувати цикли for, опис яких виглядає дуже схожим на цикли в стилі C, щоправда, без деяких відмінностей тут не обійшлося. Схема циклу при такому підході виглядає так:

For ((початкове значення змінної; умова закінчення циклу; зміна змінної))
На bash це можна написати так:

For ((a = 1; a< 10; a++))
А ось робочий приклад:

#!/bin/bash for ((i=1; i<= 10; i++)) do echo "number is $i" done
Цей код виведе список чисел від 1 до 10.

Робота циклу у стилі C

Цикл while

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

Ось схема організації циклів while
while команда перевірки умови
do
інші команди
done

Погляньмо на приклад скрипту з таким циклом:

#!/bin/bash var1=5 while [ $var1 -gt 0 ] do echo $var1 var1=$[ $var1 - 1 ] done
На вході в цикл перевіряється, чи більша за нуль змінна $var1 . Якщо це так, виконується тіло циклу, в якому значення змінної віднімається одиниця. Так відбувається в кожній ітерації, при цьому ми виводимо консоль значення змінної до його модифікації. Як тільки $var1 набере значення 0, цикл припиняється.

Результат роботи циклу while

Якщо не модифікувати змінну $var1 , це призведе до попадання скрипта в безкінечний цикл.

Вкладені цикли

У тілі циклу можна використовувати будь-які команди, зокрема - запускати інші цикли. Такі конструкції називають вкладеними циклами:

#!/bin/bash for ((a = 1; a<= 3; a++)) do echo "Start $a:" for ((b = 1; b <= 3; b++)) do echo " Inner loop: $b" done done
Нижче показано, що виведе цей скрипт. Як видно, спочатку виконується перша ітерація зовнішнього циклу, потім – три ітерації внутрішнього, після його завершення знову у справу вступає зовнішній цикл, потім знову – внутрішній.

Вкладені цикли

Обробка вмісту файлу

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

#!/bin/bash IFS=$"\n" для введення в $(cat /etc/passwd) do echo "Values ​​in $entry –" IFS=: для значення в $entry до echo " $value" done done
У цьому скрипті два цикли. Перший проходить рядками, використовуючи як роздільник знак перекладу рядка. Внутрішній зайнятий розбором рядків, поля яких розділені двокрапками.

Обробка даних файлу

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

Управління циклами

Можливо, після входу в цикл, потрібно буде зупинити його при досягненні змінної циклу певного значення, яке не відповідає заданій умові закінчення циклу. Чи потрібно буде в такій ситуації чекати нормального завершення циклу? Ні, звичайно, і в подібних випадках стануть у нагоді наступні дві команди:
  • break
  • continue

Команда break

Ця команда дозволяє перервати виконання циклу. Її можна використовувати і для циклів for , і для циклів while:

#!/bin/bash for var1 in 1 2 3 4 5 6 7 8 9 10 do if [ $var1 -eq 5 ] the break fi echo "Партнер: $var1" done
Такий цикл, у звичайних умовах, пройде по всьому списку значень зі списку. Однак, у нашому випадку, його виконання буде перервано, коли змінна $var1 дорівнюватиме 5.

Достроковий вихід із циклу for

Ось - те саме, але вже для циклу while:

#!/bin/bash var1=1 while [ $var1 -lt 10 ] do if [ $var1 -eq 5 ] then break fi echo "Iteration: $var1" var1=$(($var1 + 1)) done
Команда break , виконана, коли значення $var1 дорівнюватиме 5, перериває цикл. У консоль виведеться те саме, що й у попередньому прикладі.

Команда continue

Коли в тілі циклу зустрічається ця команда, поточна ітерація завершується достроково і починається наступна, причому виходу з циклу не відбувається. Подивимося на команду continue у циклі for:

#!/bin/bash for ((var1 = 1; var1< 15; var1++)) do if [ $var1 -gt 5 ] && [ $var1 -lt 10 ] then continue fi echo "Iteration number: $var1" done
Коли умова всередині циклу виконується, тобто коли $var1 більше 5 і менше 10, оболонка виконує команду continue . Це призводить до пропуску команд, що залишилися в тілі, і переходу до наступної ітерації.

Команда continue у циклі for

Обробка виводу, що виконується у циклі

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

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

#!/bin/bash for ((a = 1; a< 10; a++)) do echo "Number is $a" done >myfile.txt echo "finished."
Оболонка створить файл myfile.txt і перенаправить у файл висновок конструкції for . Відкриємо файл і переконаємося, що він містить саме те, що очікується.

Перенаправлення виведення циклу на файл

Приклад: пошук файлів, що виконуються.

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

#!/bin/bash IFS=: for folder in $PATH do echo "$folder:" для файлу в $folder/* do if [ -x $file ] then echo " $file" fi done done
Такий ось скрипт, невеликий і нескладний, дозволив отримати список файлів, що виконуються, що зберігаються в папках з PATH .

Пошук файлів, що виконуються в папках зі змінної PATH

Підсумки

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

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

Короткий опис різниці у типах циклів:

for - виконуватиме дію доти, доки є об'єкти для виконання (наприклад - читання потоку з stdin, файлу або функції);
while - виконує дію доти, доки умоває істинним;
until — виконуватиметься доти, доки умовастане істинним, тобто. поки воно false.

Цикл FOR

Розглянемо такий варіант скрипту із циклом:

$ cat loop.sh #!/bin/bash для variable в `ls -1` do echo "$variable" done

Синтаксис дуже простий і досить наочно показаний у прикладі:

for (запускаємо цикл) variable (оголошуємо змінну, над якою виконуватимемо дії) in (направляємо циклу потік) `ls -1` (команда, яку необхідно виконати і передати в змінну $variable). Do і done - "тіло" циклу, в рамках яких будуть виконуватися основні дії над отриманими даними, а echo "$ Variable" - безпосередньо сама дія, що виконується циклом.

Тепер трохи змінимо приклад, і замість явної вказівки команди застосуємо другу змінну:

$ cat loop.sh #!/bin/bash ls=`ls -1` for variable в $ls do echo "$variable" done

Тепер команда ls -1 передається в окремій змінній, що дозволяє гнучкіше працювати з циклом. Замість змінної у циклі можна використовувати і функцію:

$ cat loop.sh #!/bin/bash lsl () ( ls -1 ) for variable в `lsl` do echo "$variable" done

Основна умова циклу for - він виконуватиметься доти, поки в переданій йому команді є об'єкти для дії. Виходячи з прикладу вище - поки в лістингу ls -1 є файли для відображення - цикл передаватиме їх у змінну і виконуватиме "тіло циклу". Як тільки список файлів у директорії закінчиться цикл завершить своє виконання.

Давайте трохи ускладнимо приклад.

У каталозі є список файлів:

$ ls -1 file1 file2 file3 file4 file5 loop.sh nofile1 nofile2 nofile3 nofile4 nofile5

Нам необхідно вибрати з них лише ті, які в назві не мають слова. no«:

$ cat loop.sh #!/bin/bash lsl=`ls -1` для variable в $lsl do echo "$variable" | grep -v "no" done $ ./loop.sh file1 file2 file3 file4 file5 loop.sh

У циклі так само можна використовувати умовні вирази ( conditional expressions) […] для перевірки умов та оператор break для переривання циклу у разі спрацювання умови.

Розглянемо такий приклад:

$ cat loop.sh #!/bin/bash lsl=`ls -1` для variable в $lsl do if [ $variable != "loop.sh" ] then echo "$variable" | grep -v "no" else break fi done

Цикл буде виконуватися доти, доки не буде зустрінуто файл loop.sh . Як тільки виконання циклу дійде до цього файлу, цикл буде перерваний командою break:

$ ./loop.sh file1 file2 file3 file4 file5

Ще один приклад – використання арифметичних операцій безпосередньо перед виконанням тіла циклу:

$ cat loop.sh #!/bin/bash for ((count=1; count<11; count++)) do echo "$count" done

Тут ми задаємо три керуючі команди - count = 1, контролююча умова - поки count менше 11, і команду для виконання - count +1:

Цикли WHILE та UNTIL

Простий приклад, що добре демонструє принцип роботи циклу while:

$ cat loop.sh #!/bin/bash count=0 while [ $count -lt 10 ] do ((count++)) echo $count done

Ми задаємо змінну $count рівну нулю, після чого запускаємо цикл whi le з умовою «поки що $count менше десяти — виконувати цикл». У тілі циклу ми виконуємо постфіксний інкремент+1 до змінної $count та результат виводимо в stdout .

Результат виконання:

$ ./loop.sh 1 2 3 4 5 6 7 8 9 10

Як тільки значення змінної $count стало 10 цикл припинився.

Хороший приклад «нескінченного» циклу, який демонструє роботу while:

$ cat loop.sh #!/bin/bash count=10 while [ 1 = 1 ] do ((count++)) echo $count done $ ./loop.sh ... 5378 5379 5380 5381 5382 5383 ^C

Аналогічно, але «на зворотний бік» працює і цикл until:

$ cat loop.sh #!/bin/bash count=0 until [ $count -gt 10 ] do ((count++)) echo $count done

Тут ми задаємо схожу умову, але замість «поки що змінна менше 10» — вказуємо «поки що змінна не стане більше ніж 10». Результат виконання:

$ ./loop.sh 1 2 3 4 5 6 7 8 9 10 11

Якщо ж наведений вище приклад «нескінченного циклу» виконати з використанням until — не виведе нічого, на відміну від while:

$ cat loop.sh #!/bin/bash count=10 until [ 1 = 1 ] do ((count++)) echo $count done $ ./loop.sh $

Так як " умова" від самого початку " істинно» - Тіло циклу виконуватися не буде.

Як і в циклі for — у while та until можна використовувати функції. Для прикладу — цикл із скрипту, що реально використовується, виконує перевірку статусу сервера Tomcat(PID береться в системі SLES, в інших системах може відрізнятися), трохи спрощений варіант:

$ cat loop.sh #!/bin/bash check_tomcat_status () ( RUN=`ps aux | grep tomcat | grep -v grep | grep java | RUN" ] then printf "WARNING: Tomcat still running with PID $RUN." else printf "Tomcat stopped, proceeding ... nn" break fi done

Результат виконання:

$ ./loop.sh WARNING: Tomcat продовжує бігти з PID 14435 26548.WARNING: Tomcat залишається бігти з PID 14435 26548.WARNING: Tomcat йти бігати з PID 14435 26548.WAR. WARNING: Tomcat still running with PID 14435 26548.WARNING: Tomcat still running with PID 14435 26548.WARNING: Tomcat still running with PID 14435 26548.WARNING: Tomcat still running with PID 1443

Повний варіант:

Check_tomcat_status () ( RUN=`ps aux | grep tomcat | grep -v grep | grep java | awk "(print $2)"` ) while check_tomcat_status; do if [ -n "$RUN" ] then printf "WARNING: Tomcat продовжує керувати з PID $RUN. Stop it? " answer "Stopping Tomcat..." "Proceeding installation..." && $CATALINA_HOME/bin/shutdown. sh 2&>1 /dev/null || break sleep 2 if [ -n "$RUN" ] then printf "Tomcat продовжує працювати. Kill it?" break sleep 2 fi else printf "Tomcat stopped, proceeding ... nn" break fi done

Функція answer описувалася в статті, але тут використовується трохи покращений варіант:

Answer () ( while read response; do echo case $response in |) printf "$1n" return 0 break;; |) printf "$2n" return 1 break;; *) printf "Please, enter Y(yes) or N(no)! " esac done )

Тут можна було використовувати як while, так і until - але не цикл for, тому що for спрацював би один раз (отримав PID - і завершився).

Цикли - це вкрай зручна штука при написанні будь-яких програм або скриптів, скоріше навіть необхідна. Вони дозволяють нам виконувати певну ділянку коду задану кількість разів. Природно, у 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 не заданий, то як його використовується змінна $@ - список аргументів командного рядка.
При створенні списку аргументів у циклі 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 як будь-яка порядна СУБД промислового призначення разом з базою даних веде транзакційні логи, які дозволяють відкочувати стан...

0 Meeran Bala-Kumaran

Я дійсно намагаюся зрозуміти, чому цей цикл while ніколи не закінчується, коли цикл починається, моя змінна LOC встановлена ​​в Testing/, яка є каталогом, який я створив для тестування цієї програми, має наступний макет:

Я хочу, щоб цикл закінчувався, як тільки у всіх Каталогів була використана функція "count".
Ось що я пробував;

Я перевірив функцію підрахунку, і вона не створює нескінченний цикл

Я спробував запустити алгоритм вручну

PARSE=1 LOC=$LOC/ count AVAILABLEDIR=$(ls $LOC -AFl | sed "1 d" | grep "/$" | awk "( print $9 )") while [ $PARSE = "1" ] do if [[$(AVAILABLEDIR[@]) ==""]]; then PARSE=0 fi DIRBASE=$LOC для $(AVAILABLEDIR[@]); do LOC="$(DIRBASE)$(a)" LOCLIST="$LOCLIST $LOC" count done for a in $(LOCLIST[@]); do TMPAVAILABLEDIR=$(ls $a -AFl | sed "1 d" | grep "/$" | awk "( print $9 )") PREPEND=$a if [[ $(TMPAVAILABLEDIR[@]) == "" ] ]; then continue fi for a in $(TMPAVAILABLEDIR[@]); do TMPAVAILABLEDIR2="$TMPAVAILABLEDIR2 $(PREPEND[@])$(a)" done NEWAVAILABLEDIR="$NEWAVAILABLEDIR $TMPAVAILABLEDIR2" done AVAILABLEDIR=$NEWAVAILABLEDIR NEWAVAILABLEDIR=""LOC="" done

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

bash infinite-loop

4 відповіді

Ви повинні спробувати запустити скрипт з аргументом -x або записати його в перший рядок:

#!/bin/bash -x

Потім він повідомляє вам все, що він робить.

У цьому випадку ви можете помітити дві помилки:

    Ви ніколи не перезавантажуєте TMPAVAILABLEDIR2

    Ви також робите ls на звичайних файлах.

Якщо ви дійсно повинні уникати рекурсії, спробуйте це повністю без рекурсії:

#!/bin/bash count() ( echo counting "$1" ) todo=(Testing) while test $(#todo[@]) != 0 do doit=("$(todo[@])") todo= () for dir в "$(doit[@])" do entry в "$dir"/* # if dir is empty, ця стаття наведена як "*" do test -e "$entry" || continue # skip entry "*" empty dir count "$entry" test -d "$entry" || continue todo+=("$entry") done done done

Однак, будь ласка, скажіть мені, чому ви не можете використати рекурсію? Це свого роду алергія? Обітниця? Чи існують якісь локальні закони проти рекурсивного програмного забезпечення, де ви живете?

Ви написали, що хочете виконати "підрахунок" на всіх ріжках. Подивіться варіанти пошуку:

Find $LOC-type d | while read dir; do cd $LOC cd $(dir) count done

або коротше (коли ваш лічильник функцій приймає каталог як параметр 1)

Find $LOC-type d | xargs count

Тепер я бачу, що ви не хочете використати find або ls-R (рекурсивна функція). Потім ви повинні зробити свою рекурсивну функцію, на кшталт

Function parseDir ( ls -d */ $1 | while read dir; do count parseDir $1/$dir done )

Я гадки не маю, чи буде це працювати, але його цікаве питання, про яке я не міг перестати думати. Успіхів

While true; do for word в "$(echo *)"; do if [[ -d "$word"]] ; then d[$((i++))]="$PWD"/"$word" elif [[ -f "$word" ]] ;then f[$((j++))]="$PWD"/"$ word" fi done [[ $k -gt $i ]] && cd .. cd "$d[$((k++))]" || break done



Розповісти друзям