Для виходу з циклу bash. Чому цикл for не виконується у каталозі

Для виходу з циклу bash. Чому цикл for не виконується у каталозі

Оболонка 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

Оболонка 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

Одне з основних правил системного адміністрування можна висловити так: якщо вам потрібно часто робити те саме, напишіть сценарій, і нехай він робить цю роботу за вас. Якщо вам необхідно виконувати якусь дію всередині сценарію кілька разів, вам варто скористатися циклами. У 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. Частина 2.
Вибачаюсь за таку велику затримку між статтями, але сесія дається взнаки в самий невідповідний момент:)
Всім дякую за зауваження, критику та доповнення, які були озвучені у коментарях до минулої статті.
Ця частина, як і обіцяв, буде присвячена циклам, математичним операціям та використанню зовнішніх команд.
Почнемо.

Цикли. Цикл for-in.

Оператор for-in призначений для почергового звернення до значень, перелічених у списку. Кожне значення по черзі у списку надається змінною.
Синтаксис наступний:
for змінна in список_значень
do
команди
done

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

#!/bin/bash
for i in 0 1 2 3 4 #змінною $i будемо по черзі надавати значення від 0 до 4 включно
do
echo "Console number is $i" >> /dev/pts/$i #Пишемо у файл /dev/pts/$i(файл віртуального терміналу) рядок "Console number is $i"
done #цикл закінчено
exit 0

Після виконання прикладу в перших 5 віртуальних консолях (терміналах) з'явиться рядок із номером. У змінну $i по черзі підставляються значення зі списку і в циклі йде робота зі значенням цієї змінної

Цикли. Цикл while.

Цикл while складніший за цикл for-in і використовується для повторення команд, поки якийсь вираз істинно (код повернення = 0).
Синтаксис оператора наступний:
while вираз або команда, що повертає код повернення
do
команди
done

Приклад роботи циклу розглянемо на прикладі:

#!/bin/bash
again=yes #надаємо значення "yes" змінної again
while [ "$again" = "yes" ] #Будемо виконувати цикл, поки $again буде рівно "yes"
do
echo "Продовжити назви:"
read name
echo "Виберіть це ім'я $name"

Echo "Do you wish to continue?"
read again
done
echo "Bye-Bye"


А тепер результат роботи скрипту:
ite@ite-desktop:~$./bash2_primer1.sh
Please enter a name:
ite
The name you entered is ite
Do you wish to continue?
yes
Please enter a name:
mihail
The name you entered is mihail
Do you wish to continue?
no
Bye-Bye

Як бачимо цикл виконується до того часу, поки ми введемо щось відмінне від «yes». Між do і done можна описувати будь-які структури, оператори і т.п., всі вони будуть виконуватися в циклі. потрапити у нескінченний цикл.
Тепер про умову істинності. Після while, як і в умовному операторі if-then-else, можна вставляти будь-який вираз або команду, яка повертає код повернення, і цикл буде виконатися до тих пір, поки код повернення = 0! Оператор "[" аналог команди test, яка перевіряє істинність умови, яку їй передали.

Розглянемо ще один приклад, я взяв його з книги Advanced Bash Scripting. Дуже він мені сподобався:), але я його трохи спростив. У цьому прикладі ми познайомимося із ще одним типом циклів UNTIL-DO. Ця практично повний аналог циклу WHILE-DO, тільки виконується поки якийсь вираз хибно.
Ось приклад:

#!/bin/bash
echo "Введіть чисельник: "
read dividend
echo "Введіть знаменник: "
read divisor

Dnd=$dividend #ми змінюватимемо змінні dividend і divisor,
# Збережемо їх знання інших змінних, т.к. вони нам
#потрібні
dvs=$divisor
remainder=1

Until [ "$remainder" -eq 0 ]
do
let "remainder = dividend % divisor"
dividend=$divisor
divisor=$remainder
done

Echo "НОД чисел $dnd і $dvs = $dividend"


Результат виконання скрипту:
ite@ite-desktop:~$./bash2_primer3.sh
Введіть чисельник:
100
Введіть знаменник:
90
НОД чисел 100 і 90 = 10

Математичні операції

Команда let.
Команда let проводить арифметичні операції над числами та змінними.
Розглянемо невеликий приклад, у якому ми робимо деякі обчислення над введеними числами:
#!/bin/bash
echo "Введіть a: "
read a
echo "Введіть b: "
read b

Let "c = a + b" #додавання
echo "a+b= $c"
let "c = a / b" #поділ
echo "a/b= $c"
let "c<<= 2" #сдвигает c на 2 разряда влево
echo "c після зсуву на 2 розряди: $c"
let "c = a % b" # знаходить залишок від розподілу a на b
echo "$a / $b. залишок: $c "


Результат виконання:
ite@ite-desktop:~$./bash2_primer2.sh
Введіть a:
123
Введіть b:
12
a+b= 135
a/b= 10
c після зсуву на 2 розряди: 40
123/12. залишок: 3

Ну ось, як бачите нічого складного, список математичних операцій стандартний:
+ - додавання
- - віднімання
* - множення
/ - розподіл
** - зведення в ступінь
% - модуль(розподіл по модулю), залишок від розподілу
let дозволяє використовувати скорочення арифметичних команд, тим самим скорочуючи кількість використовуваних змінних. Наприклад: a = a+b еквівалентно a +=b тощо.

Робота із зовнішніми програмами при написанні shell-скриптів

Спочатку трохи корисної теорії.
Перенаправлення потоків.
У bash(як і багатьох інших оболонках) є вбудовані файлові дескриптори: 0(stdin), 1(stdout), 2(stderr).
stdout – Стандартний висновок. Сюди потрапляє все, що виводять програми
stdin - Стандартне введення. Це все що набирає користувач у консолі
stderr – стандартний висновок помилок.
Для операцій із цими дескрипторами, існують спеціальні символи: > (перенаправлення вывода),< (перенаправление ввода). Оперировать ими не сложно. Например:
перенаправити висновок команди cat /dev/random в /dev/null (абсолютно марна операція:))) або
записати у файл listing зміст поточного каталогу (вже корисніше)
Якщо є необхідність дописувати до файлу (при використанні ">" він заміняєтеся), необхідно замість ">" використовувати ">>"
після прохання sudo ввести пароль, він візьметься з файлу my_password, ніби ви його запровадили з клавіатури.
Якщо необхідно записати у файл лише помилки, які могли виникнути під час роботи програми, можна використовувати:
./program_with_error 2> error_file
цифра 2 перед ">" означає, що потрібно перенаправляти все, що потрапить в дескриптор 2(stderr).
Якщо потрібно змусити stderr писати в stdout, це можна можна слід. чином:
символ & означає вказівник на дескриптор 1(stdout)
(За замовчуванням stderr пише на ту консоль, в якій працює користувач (вірніше пише на дисплей)).
2.Конвеєри.
Конвейєр – дуже потужний інструмент для роботи з консоллю Bash. Синтаксис простий:
команда1 | команда 2 - означає, що виведення команди 1 передадуть на введення команді 2
Конвейєри можна групувати в ланцюжки і виводити за допомогою перенаправлення у файл, наприклад:
ls-la | grep "hash" | sort > sortilg_list
висновок команди ls -la передається команді grep, яка відбирає всі рядки, в яких зустрінеться слово hash, і передає команді сортування sort, яка пише результат файл sorting_list. Все досить зрозуміло та просто.

Найчастіше скрипти на Bash використовуються як автоматизація якихось рутинних операцій у консолі, звідси іноді виникає необхідність в обробці stdout однієї команди і передача на stdin іншій команді, при цьому результат виконання однієї команди повинен бути якимось чином оброблений. У цьому розділі я спробую пояснити основні принципи роботи із зовнішніми командами всередині скрипту. Думаю, що прикладів я навів досить і можна тепер писати лише основні моменти.

1. Передача виведення змінну.
Для того щоб записати в змінну висновок будь-якої команди, достатньо укласти команду в `` ковечки, наприклад
a = `echo "qwerty"`
echo $a

Результат роботи: qwerty


Однак якщо ви захочете записати в змінну список директорій, то необхідно належним чином обробити результат для розміщення даних у змінну. Розглянемо невеликий приклад:
LIST=`find /svn/ -type d 2>/dev/null| awk "(FS="/") (print $4)"| sort|uniq | tr "\n" " "`
for ONE_OF_LIST у $LIST
do
svnadmin hotcopy /svn/$ONE_OF_LIST /svn/temp4backup/$ONE_OF_LIST
done

Тут ми використовуємо цикл for-do-done для архівування всіх директорій у папці /svn/ за допомогою команди svnadmin hotcopy (що в нашому випадку не має нікого значення, просто як приклад). Найбільший інтерес викликає рядок: LIST = find / svn / -type d 2> / dev / null | awk "(FS="/") (print $4)"| sort|uniq | tr "\n" " "` У ній змінної LIST присвоюється виконання команди find, обробленої командами awk, sort, uniq,tr (всі ці команди ми не розглядатимемо, бо це окрема стаття). У змінній LIST будуть імена всіх каталогів у папці /svn/ пгомещенных в один рядок(щоб її стравити циклу.

Як видно, все не складно, достатньо зрозуміти принцип та написати пару своїх скриптів. Наприкінці статті хочу побажати успіхів у вивченні BASH і Linux загалом. Критика, як водиться вітається. Наступна стаття може бути присвячена використанню таких програм як sed, awk.

На цій лекції ми продовжуємо знайомитись з 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:

igor@ubuntu:~/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 $@
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і $@ .$# - Повертає кількість параметрів переданих функції. У нашому прикладі це буде число 3 .$@ повертає всі параметри одним рядком. У прикладі це буде a b c. А через $1 , $2 , $3 і т.д. можна звертатися до кожного параметра персонально. $? - Містить код виконання останньої команди. У прикладі код виконання функції.

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

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

 

 

Це цікаво: