Доброго дня! В даній статті висвітлено синтаксис і приклад створення функцій в командному інтерпретаторі Bash.

Синтаксис

Shell-функція являється об'єктом, який викликається як звичайна команда і виконує складені команди з новим набором позиційних параметрів (параметрів скрипта командного рядка). Функції оголошуються наступним чином:
[ function ] ім'я_функції () складена-команда [перенаправлення]
В квадратних дужках вказуються необов'язкові елементи; в іменах функцій і змінних не можна використовувати апострофи. Даний синтаксис визначає нову функцію з назвою “ім'я_функції”. Зарезервоване слово “function” являється необов'язковим. Якщо вказане зарезервоване слово “function”, дужки являються необов'язковими. Тіло функції являється складеною командою “складена-команда” (яка може розміщуватися між “()”, “(())”, “[]”, “[[]]”, “{}”, операторами вибору і циклів, а також оператором select). Зазвичай, ця команда являється списком команд, які розміщені між фігурними дужками “{}”, але також вони можуть розміщуватись і між іншими операторами. Команди з списку “складена-команда” виконуються у випадку вказування імені “ім'я_функції” в якості ім'я простої команди. Будь-які перенаправлення потоків, які вказані під час оголошення функції, виконуються під час її виконання. Статус виходу операції оголошення функції являється нульовим, окрім випадків синтаксичних помилок або оголошень функцій з однаковим іменем. Після виклику функції, статус виходу являється статусом виходу останньої команди виконаної в її тілі. Функції виконуються в контексті поточного командного інтерпретатора; для її інтерпретування не створюється новий процес. Під час виклику функції, аргументи до функції стають позиційними параметрами під час її виконання. Спеціальний параметр “#” оновлюється для відображення відповідних змін. Спеціальний параметр “0” залишається незмінним. Перший елементи змінної FUNCNAME встановлюється у ім'я функції під час її виконання. Усі інші аспекти виконання командного рядка є ідентичними між функцією і її клієнтом, окрім пасток DEBUG і RETURN, які не успадковуються від клієнта, якщо у неї не встановлений атрибут trace або не увімкнений прапорець -o functrace за допомогою вбудованої команди set. Локальні змінні функції можуть бути оголошеними за допомогою вбудованої команди local. Зазвичай, змінні і їхні значення розділяються між функцією і її клієнтом (скриптом загалом). Якщо використана вбудована команда return виконана всередині тіла функції, функція завершує своє виконання і управління передається наступній команді, яка стоїться після місця виклику функції. Будь-яка команда, яка асоціюється з пасткою RETURN, виконується перед продовженням виконання скрипта. Під час завершення виконання функції, значення позиційних параметрів і спеціального параметру “#” відновлюється до тих, які вони мали перед викликом функції. Імена функції і їх оголошення можуть бути переглянутими за допомогою команди declare або typeset з переданим їм прапорцем -f. Прапорець -F, переданий до команди declare або typeset спричинить дані команди відобразити тільки імена функцій (і файл, в якому вони були оголошеними, якщо увімкнена опція командного рядка extdebug). Функції можуть бути експортованими до дочірніх процесів командного інтерпретатора за допомогою вбудованої команди export з прапорцем -f. Функцію можна знищити за допомогою вбудованої команди unset з переданим прапорцем -f. Зауважте, що shell-функції і змінні з однаковим ім'ям можуть спричинити існування множинних об'єктів, переданих до потомків командного інтерпретатора. Це необхідно враховувати у місцях, де така ситуація може спричинити проблеми. Функції можуть бути рекурсивними. Жодні обмеження не накладаються на кількість рекурсивних викликів.

Приклад

Розглянемо приклад який імітує виконання стандартної Юнікс-команди find:
find ./ -writable
На чому ще вивчати мову програмування, якщо не на велосипедах? Дана команда (з вказаними параметрами) шукає в поточній директорії і її дочірніх директоріях файли і директорії, які поточному користувачу дозволено перезаписувати. Вміст такого скрипта може бути наступним:
#!/bin/bash

# оголошуємо функцію, яка виводить на екран файли,
# які поточному користувачу дозволено перезаписувати
print_writtable_files ()
{
  # оголошуємо локальну змінну функції
  # для утримування і зміни значення шляху
  local dpath=$1
  
  # перевіряємо чи існує директорія
  # якщо ні - завершуємо виконання функції
  if [[ ! -d $dpath ]]
  then 
    echo "файл $dpath не існує, або не являється директорією"
    return 1
  fi
  
  # якщо в кінці шляху до директорії немає слешу
  # - додаємо його
  if [[ ! $dpath = */ ]]; then
    dpath="$dpath"/
  fi
  
  # отримуємо усі файли в директорії за шляхом dpath
  # і тестуємо кожен отриманий елемент на те що він є:
  #  - aбо директорія (рекурсія для її тестів)
  #  - або файл, у який можна виконувати запис
  for fname in "$dpath"*
  do
  
    # якщо шлях fname являється символічним посиланням
    # - не тестуємо його
    if [[ -h "$fname" ]] ; then continue ; fi
  
    # тестуємо файл на можливість запису
    # якщо він доступний для запису - 
    # виводимо його шлях на екран
    if [[ -w "$fname" ]] ; then
      echo "$fname"
    fi ;
    
    # якщо за шляхом fname знаходиться директорія
    # рекурсивно викликаємо дану функцію,
    # щоб протестувати усю файлову систему 
    # відносно початкової директорії
    if [[ -d "$fname" ]] ; then
      print_writtable_files "$fname"
    fi ;
    
  done ;
}

# перевіряємо чи користувач передав валідний шлях до директорії
# якщо ні - завершуємо роботу скрипта
if [[ ! -d "$1" ]] ; then
  echo "Шлях '$1' не являється валідним параметром для скрипта."
  echo "Передайте шлях до існуючої директорії"
  exit 1
fi

# отримуємо абсолютний канонічний шлях до вказаної директорії
testdpath=$(readlink -f "$1")

# виклик функції, яка рекурсивно тестує файли і директорії
print_writtable_files "$testdpath"
В загальному скрипт оголошує функцію print_writtable_files, перевіряє валідність шляху до директорії, яку користувач бажає протестувати на доступні для запису файли і директорії, після чого передає абсолютний шлях до цієї директорії в оголошену функцію. Більш детально в коментаріях. Виконання даного скрипта може виглядати наступним (скрипт знаходиться у файлі function.sh): bash_simple_shell_function_script_output