BASH. Умови, цикли, функції.
Основи роботи з Linux. -> BASH. Умови, цикли, функції.
BASH. Умови, цикли, функції.
Умови
Базова форма.
if [[ "$some_variable" == "good input" ]]; then
echo "You got the right input."
elif [[ "$some_variable" == "ok input" ]]; then
echo "Close enough"
else
echo "No way Jose."
fi
fi надає пропозиції трохи екзотичний вигляд
Якщо (if) щось є істиною, тоді (then) виконай ось це. В іншому випадку перевіряй інші умови по порядку і роби те саме.
Якщо жодна з умов не спрацювала, виконай останню вказівку.
Можна відкинути одну або всі гілки elif, а також гілку else, якщо в них немає потреби!
Булеві оператори.
! - ні
&& - і
|| - або
Наприклад.
if [[ "$name" == "Ryan" ]] && ! [[ "$time" -lt 2000 ]]; then
Іноді квадратні дужки можуть бути одинарними
if ["$age"-gt 30]; then
А іноді й круглими.
if (( age > 30 )); then
А іноді їх взагалі немає
if is_upper "$1"; then
Є магічні слова, які стоять за роботою if в Bash: коди виходу.
Вміст відразу після if може бути будь-якою командою, якщо вона дає код виходу.
Якщо команда повертає код виходу 0 (в Bash це код успішно виконаної операції), тоді запускається код усередині гілки then.
Існує спеціальна команда - [(ліва квадратна дужка). Вона є синонімом команди test і є вбудованою командою (тобто більш ефективною, в сенсі продуктивності). Ця команда сприймає свої аргументи як вираз порівняння або як файлову перевірку і повертає код завершення відповідно до результатів перевірки (0 – істина, 1 – брехня).
Починаючи з версії 2.02, Bash надає у розпорядження програміста конструкцію [[…]] розширений варіант команди test, яка виконує порівняння способом більш знайомим програмістам, які пишуть іншими мовами програмування. Подвійні квадратні дужки працюють загалом так само, як і одинарні квадратні дужки, але мають додаткові можливості на кшталт кращої підтримки регулярних виразів.
Круглі дужки (( … )) і пропозиція let … також повертають код 0, якщо результатом арифметичного виразу є ненульове значення.
(( Подвійні круглі дужки )) це конструкція, що дозволяє здійснювати арифметичні обчислення всередині Bash. Ними можна швидко інкрементувати лічильники та оновлювати числові змінні.
count=0
(( count++ ))
Якщо результат у дужках дорівнює нулю, повертається код виходу 1 (по суті нульовий результат це «брехня»). Будь-який інший результат вважається істиною, за нього код виходу буде 0.
Знаки «більше» і «менше» усередині круглих дужок працюють чудово коли як у квадратних плутаються з переправленням виведення.
Приклади.
Намагаємось змінити поточний каталог.
if cd /tmp
then
echo "Success!!!"
ls -l
fi
Працюємо з конвейєром команд.
if ls | grep pdf
then
....
fi
При конвейєрі тільки остання команда визначає, чи буде вибрано гілку.
if ls | grep pdf | wc
Перевіряємо на існування файл.
if [[ -e $FILENAME ]]
then
...
fi
Список додаткових випробувань.
Оператори перевірки файлів
-d - чи існує файл
-r - чи існує файл і чи він доступний для читання
-w - чи існує файл і чи він доступний для запису
-x - чи існує файл і чи він виконуваний
Числові тестові оператори.
-eq - равно
-gt - більше
-lt - менше
Подвійні дужки
if (( VAL < 12 ))
Усередині дужок не потрібен оператор $ для отримання значення, за винятком позиційних параметрів $1, $2 і т.д. (щоб не плутати їх із константами 1 2 і т.д.)
У подвійних дужках будь-яке ненульове значення є істинним і лише нуль - хибним.
Аналіз результату виконання попередньої команди
if (( $? )) ; then ... ; fi
Розподіл команд.
Команди в BASH можна писати в один рядок розділяючи; && або ||
Приклади
cd $DIR; ls - команди виконуються одна за одною
cd $DIR && ls - команда ls виконається у разі успішної першої
cd $DIR || ls - команда ls виконається у разі збою першої
Можна використовувати тести [[]] не тільки в конструкціях if
[[ -d $DIR ]] && ls "$DIR"
Цикли
Цикл з оператором while по структурі схожий на if у тому сенсі, що для прийняття рішення він може приймати одну команду або конвеєр команд, які видають true або false.
У ньому також можна використовувати квадратні або круглі дужки, як у попередніх прикладах.
У деяких мовах програмування фігурні дужки (символи {}) призначені для угруповання операторів, які знаходяться в тілі циклу while.
У таких мовах програмування, як Python, тіло циклу та його оператори визначаються відступом.
У bash оператори згруповані між двома ключовими словами: do та done .
Ось простий цикл while:
i=0
while (( i < 1000 ))
do
echo $i
let i++
done
let - це вбудована функція BASH яка виконує арифметичні операції.
Аналогічно можна скористатися круглими дужками.
(( i++ ))
Синтакс
let arg [arg ...]
При цьому let виконує арифметичні операції з усіма переданими аргументами зліва направо.
Список деяких арифметичних операторів.
** var++ var– ++var –var ** - додавання, віднімання, причому з перед і пост інтерпретацією.
! - Логічне заперечення
** *, /, % ** - множення, розподіл, модуль
<<, >> - побітове зміщення
Ось більш складний цикл while, який виконує команди як частину своєї умови:
while ls | grep -q pdf
do
echo -n 'there is a file with pdf in its name here:'
pwd
cd ..
done
grep -q - при пошуку мовчазно ігнорувати помилки
echo -n - не виводити символи перенесення рядків
Цикл for також доступний bash, причому в трьох варіантах.
Варіант 1.
for ((i=0; i < 100; i++))
do
echo $i
done
Варіант 2.
for ARG
do
echo here is an argument: $ARG
done
ARG - можна замінити будь-якою змінною.
Результат виводу.
$ ./args.sh bash is fun
here is an argument: bash
here is an argument: is
here is an argument: fun
Варіант 3 із явним завданням аргументів.
for VAL in 20 3 dog peach 7 vanilla
do
echo $VAL
done
Значення, вказані в циклі for , також можна генерувати, викликаючи інші програми або за допомогою інших функцій оболонки:
for VAL in $(ls | grep pdf) {0..5}
do
echo $VAL
done
$(ls | grep pdf) - викликає команду у підболочці.
{0..5} - визначення діапазону, можна з кроком {1..104..2}
Тут змінна VAL , у свою чергу, буде набувати значення для кожного файлу, який командою ls передається в grep і містить літери pdf у своєму імені (наприклад, doc.pdf або notapdfile.txt ), а потім змінна VAL прийме значення кожного числа від 0 до 5
Функції.
Синтаксис функції bash наступний:
function myfun ()
{
# це тіло функції
}
Не всі ці компоненти є обов’язковими. Ви можете вказати або function, або ().
У визначенні функції параметри не оголошуються. Які б аргументи та їх кількість при виклику функції не наводилася, вони передаються цією функції.
Функція викликається (активізується) так само, як і будь-яка команда у командній оболонки. Визначивши myfun як функцію, ви можете викликати її так:
myfun 2 arb "14 years"
Усередині визначення функції аргументи згадуються так само, як параметри сценарію оболонки, тобто як $1, $2 і т.д.
Це означає, що аргументи приховують параметри, спочатку передані в сценарій.
Якщо ви хочете отримати доступ до першого параметра скрипта, перед викликом функції потрібно зберегти $1 у змінній (або передати його як параметр функції).
Якщо вказана всередині функції команда не оголошена як local, змінні у видимій галузі є глобальними. Так само як і змінні теж глобальні, якщо явно не визначені як локальні.
Виклик функції у підболочці.
RETVAL = $ (myfunc args)
Але тут слід пам’ятати що зміни всіх світових змінних будуть актуальні тільки для підболочки, а не в поточному екземплярі.
$# - видає кількість аргументів, переданих функції
Значення, що повертається.
Функції, як і команди, повинні повертати статус: 0 якщо все йде добре, і значення, відмінне від нуля, якщо відбулася помилка.
Шаблон відповідності у BASH. 3 підстановочні символи * ? [].
Шаблони не є регулярними виразами, не плутайте їх. Наприклад точка тут типовий знак.
Шаблони порівнюються з файлами у файловій системі.
Коли командному рядку потрібно перерахувати багато файлів, необов’язково вводити ім’я кожного. Bash забезпечує зіставлення з шаблоном (іноді зване підстановкою знаків (wildcarding)), щоб ви могли вказати набір файлів з шаблоном.
Найпростіший знак підстановки — символ зірочки ( * ), який буде відповідати будь-якій кількості будь-яких символів.
Наприклад
*.txt - відповідає будь-якому файлу з розширенням txt.
/usr/bin/g* - відповідає всім файлам /usr/bin , які починаються з літери g
Якщо при зіставленні необхідно враховувати *, його необхідно екранувати знаком .
/tmp/\*.out
Інший спеціальний символ для зіставлення — знак питання (?) який відповідає одному символу.
Наприклад, source.? буде відповідати source.c чи source.o, але не source.py чи source.cpp.
Останній із трьох підстановочних знаків зіставлення — квадратні дужки: [ ].
Зіставлення може бути виконане з будь-яким із символів, перерахованих у квадратних дужках.
Так, шаблон x[abc]y відповідає будь-якому чи всім файлам з іменами xay , xby або xcy за умови, що вони існують.
Ви можете вказати діапазон квадратних дужок, наприклад: [0–9] для всіх цифр.
Якщо перший символ у дужках — знак оклику ( ! ) або «капелюшок» ( ^ ), то шаблон визначає все що завгодно, крім символів, що залишилися в дужках.
[^aeiou] — будь-які символи (включаючи цифри та знаки пунктуації), крім голосних.
Таблиця класів символів.
[:alnum:] Алфавітно-цифровий
[:alpha:] Літерний
[:ascii:] ASCII (американський стандартний код для обміну інформацією)
[:blank:] Пробіл та символ табуляції
[:ctrl:] Керуючий символ
[:digit:] Число
[:graph:] Все что угодно, кроме управляющих символов и пробела
[:lower:] Символы в нижнем регистре
[:print:] Все, кроме управляющих символов
[:punct:] Символи пунктуації
[:space:] Пробіли, включаючи розриви рядків
[:upper:] Символи у верхньому регістрі
[:word:] Літери, цифри та символ підкреслення
[:xdigit:] Шістнадцятковий символ
Приклад.
*[[:punct:]]jpg
Відповідає будь-якому імені файлу, що має будь-яку кількість будь-яких символів, за якими йдуть знаки пунктуації, а за ними – літери jpg.
Таким чином, він буде відповідати файлам з іменами wow! Jpg, some, jpg або photo.jpg , але не файл this.is.myjpg , тому що прямо перед jpg немає знаку пунктуації.
Практика. Пошук файлів зазначеного типу.
Створимо сценарій для пошуку з наступними параметрами.
Сигнатура:
typesearch.sh [-c dir] [-i] [-R|r] <pattern> <path>
-c Копіювати знайдені файли до каталогу
-i Ігнорувати регістр
-R|r Рекурсивний пошук підкаталогів
Сперва определим переменную глубины поиска по умолчанию.
DEEPORNOT="-maxdepth 1"
Анализ аргументов командной строки.
while getopts 'c:irR' opt; do
case "${opt}" in
c) # копировать найденные файлы в указанный каталог
COPY=YES
DESTDIR="$OPTARG"
;;
i) # игнорировать регистр при поиске
CASEMATCH='-i'
;;
[Rr]) # рекурсивно
unset DEEPORNOT;;
*) # неизвестный/неподдерживаемый вариант
# при получении ошибки mesg от gretops просто выйти
exit 2 ;;
esac
done
‘c:irR’ - двокрапка вказує на присутність аргумент для параметра
;; - обмежувач в операторі вибору case
Коли команда getopts аналізує параметр із зазначеним вище аргументом, вона поміщає цей параметр змінну з ім’ям OPTARG.
Ми її зберігаємо в DESTDIR, тому що при наступному виклику getopts змінна OPTARG може бути змінена.
Пошук та копіювання файлів.
shift $((OPTIND - 1))
PATTERN=${1:-PDF document}
STARTDIR=${2:-.}
# по умолчанию начать здесь
find $STARTDIR $DEEPORNOT -type f | while read FN
do
file $FN | egrep -q $CASEMATCH "$PATTERN"
if (( $? == 0 ))
# найден один
then
echo $FN
if [[ $COPY ]]
then
cp -p $FN $DESTDIR
fi
fi
done
Закінчивши аналіз параметрів, ми можемо позбавитися аргументів, оброблених за допомогою shift.
Разове виконання shift позбавляє лише одного аргументу.
У цьому випадку аргумент, розташований другим, стає першим, третій стає другим і т.д. повторень команди shift, наприклад shift5, дозволить позбутися перших п’яти аргументів і в результаті аргумент $6 стане $1, $7 стане $2 і т.д
shift $((OPTIND - 1)) - ми зрушуємо
${1:-PDF document} - за допомогою : задаємо значення за замовчуванням якщо параметр не заданий
-type f - шукати лише прості файли (не каталоги)
read - команда, яка читає вміст рядка у змінну
find $STARTDIR $DEEPORNOT -type f | while read FN
Передаємо знайдені файли в while і read-ом присвоюємо змінної FN