Перейти к содержимому

Bash-скрипты: функции и разработка библиотек

Занимаясь разработкой bash-скриптов, вы рано или поздно столкнётесь с тем, что вам периодически приходится использовать одни и те же фрагменты кода. Постоянно набирать их вручную скучно, а копирование и вставка — не наш метод. Как быть? Хорошо бы найти средство, которое позволяет один раз написать блок кода и, когда он понадобится снова, просто сослаться на него в скрипте.

Оболочка bash предоставляет такую возможность, позволяя создавать функции. Функции bash — это именованные блоки кода, которые можно повторно использовать в скриптах.

Объявление функций

Функцию можно объявить так:

Или так:

Функцию можно вызвать без аргументов и с аргументами.

Использование функций

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

Здесь создана функция с именем  «myfunc». Для вызова функции достаточно указать её имя.

Результаты вызова функции

Функцию можно вызывать столько раз, сколько нужно. Обратите внимание на то, что попытавшись использовать функцию до её объявления, вы столкнётесь с ошибкой. Напишем демонстрирующий это скрипт:

Как и ожидается, ничего хорошего после его запуска не произошло.

Попытка воспользоваться функцией до её объявления

Придумывая имена для функций, учитывайте то, что они должны быть уникальными, иначе проблем не избежать. Если вы переопределите ранее объявленную функцию, новая функция будет вызываться вместо старой без каких-либо уведомлений или сообщений об ошибках. Продемонстрируем это на примере:

Как видно, новая функция преспокойно затёрла старую.

Переопределение функции

Использование команды return

Команда  «return» позволяет задавать возвращаемый функцией целочисленный код завершения. Есть два способа работы с тем, что является результатом вызова функции. Вот первый:

Команда  «echo» вывела сумму введённого числа и числа 10.

Вывод значения, возвращаемого функцией

Функция  myfunc добавляет 10 к числу, которое содержится в переменной  «$value», значение которой задаёт пользователь во время работы сценария. Затем она возвращает результат, используя команду  return. То, что возвратила функция, выводится командой  echo с использованием переменной  «$?». Если вы выполните любую другую команду до извлечения из переменной  $? значения, возвращённого функцией, это значение будет утеряно. Дело в том, что данная переменная хранит код возврата последней выполненной команды.

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

Запись вывода функции в переменную

Ещё один способ возврата результатов работы функции заключается в записи данных, выводимых функцией, в переменную. Такой подход позволяет обойти ограничения команды  return и возвращать из функции любые данные. Рассмотрим пример:

Вот что получится после вызова данного скрипта.

Запись результатов работы функции в переменную

Аргументы функций

Функции bash можно воспринимать как небольшие фрагменты кода, которые позволяют экономить время и место, избавляя нас от необходимости постоянно вводить с клавиатуры или копировать одни и те же наборы команд. Однако, возможности функций гораздо шире. В частности, речь идёт о передаче им аргументов.

Функции могут использовать стандартные позиционные параметры, в которые записывается то, что передаётся им при вызове. Например, имя функции хранится в параметре  «$0», первый переданный ей аргумент — в  «$1», второй — в  «$2», и так далее. Количество переданных функции аргументов можно узнать, обратившись к переменной  «$#».

Аргументы передают функции, записывая их после её имени:

Вот пример, в котором функция вызывается с аргументами и занимается их обработкой:

Запустим скрипт.

Вызов функции с аргументами

Функция  «addnum» проверяет число переданных ей при вызове из скрипта аргументов. Если их нет, или их больше двух, функция возвращает значение -1. Если параметр всего один, она прибавляет его к нему самому и возвращает результат. Если параметров два, функция складывает их.

Обратите внимание на то, что функция не может напрямую работать с параметрами, которые переданы скрипту при его запуске из командной строки. Например, напишем такой сценарий:

При его запуске, а точнее, при вызове объявленной в нём функции, будет выведено сообщение об ошибке.

Функция не может напрямую использовать параметры, переданные сценарию

Вместо этого, если в функции планируется использовать параметры, переданные скрипту при вызове из командной строки, надо передать их ей при вызове:

Теперь всё работает правильно.

Передача функции параметров, с которыми запущен скрипт

Работа с переменными в функциях

Переменные, которыми мы пользуемся в сценариях, характеризуются областью видимости. Это — те места кода, из которых можно работать с этими переменными. Переменные, объявленные внутри функций, ведут себя не так, как те переменные, с которыми мы уже сталкивались. Они могут быть скрыты от других частей скриптов.

Существуют два вида переменных:

  • Глобальные переменные.
  • Локальные переменные.

▍Глобальные переменные

Глобальные переменные — это переменные, которые видны из любого места bash-скрипта. Если вы объявили глобальную переменную в основном коде скрипта, к такой переменной можно обратиться из функции.

Почти то же самое справедливо и для глобальных переменных, объявленных в функциях. Обращаться к ним можно и в основном коде скрипта после вызова функций.

По умолчанию все объявленные в скриптах переменные глобальны. Так, к переменным, объявленным за пределами функций, можно без проблем обращаться из функций:

Вот что выведет этот сценарий.

Обращение к глобальной переменной из функции

Когда переменной присваивается новое значение в функции, это новое значение не теряется когда скрипт обращается к ней после завершения работы функции. Именно это можно видеть в предыдущем примере.

Что если такое поведение нас не устраивает? Ответ прост — надо использовать локальные переменные.

▍Локальные переменные

Переменные, которые объявляют и используют внутри функции, могут быть объявлены локальными. Для того, чтобы это сделать, используется ключевое слово  «local» перед именем переменной:

Если за пределами функции есть переменная с таким же именем, это на неё не повлияет. Ключевое слово  local позволяет отделить переменные, используемые внутри функции, от остальных переменных. Рассмотрим пример:

Запустим скрипт.

Локальная переменная в функции

Здесь, когда мы работаем с переменной  «$temp» внутри функции, это не влияет на значение, назначенное переменной с таким же именем за её пределами.

Передача функциям массивов в качестве аргументов

Попробуем передать функции в качестве аргумента массив. Сразу хочется сказать, что работать такая конструкция будет неправильно:

Неправильный подход к передаче функциям массивов

Как видно из примера, при передаче функции массива, она получит доступ лишь к его первому элементу.

Для того, чтобы эту проблему решить, из массива надо извлечь имеющиеся в нём данные и передать их функции как самостоятельные аргументы. Если надо, внутри функции полученные ей аргументы можно снова собрать в массив:

Запустим сценарий.

Сборка массива внутри функции

Как видно из примера, функция собрала массив из переданных ей аргументов.

Рекурсивные функции

Рекурсия — это когда функция сама себя вызывает. Классический пример рекурсии — функция для вычисления факториала. Факториал числа — это произведение всех натуральных чисел от 1 до этого числа. Например, факториал 5 можно найти так:

Если формулу вычисления факториала написать в рекурсивном виде, получится следующее:

Этой формулой можно воспользоваться для того, чтобы написать рекурсивную функцию:

Проверим, верно ли работает этот скрипт.

Вычисление факториала

Как видите, всё работает как надо.

Создание и использование библиотек

Итак, теперь вы знаете, как писать функции и как вызывать их в том же скрипте, где они объявлены. Что если надо использовать функцию, тот блок кода, который она собой представляет, в другом скрипте, не используя копирование и вставку?

Оболочка bash позволяет создавать так называемые библиотеки — файлы, содержащие функции, а затем использовать эти библиотеки в любых скриптах, где они нужны.

Ключ к использованию библиотек — в команде  «source». Эта команда используется для подключения библиотек к скриптам. В результате функции, объявленные в библиотеке, становятся доступными в скрипте, в противном же случае функции из библиотек не будут доступны в области видимости других скриптов.

У команды  source есть псевдоним — оператор «точка». Для того, чтобы подключить файл в скрипте, в скрипт надо добавить конструкцию такого вида:

Предположим, что у нас имеется файл  «myfuncs», который содержит следующее:

Это — библиотека. Воспользуемся ей в сценарии:

Вызовем его.

Использование библиотек

Только что мы использовали библиотечную функцию внутри скрипта. Всё это замечательно, но что если мы хотим вызвать функцию, объявленную в библиотеке, из командной строки?

Вызов bash-функций из командной строки

Если вы освоили предыдущую часть из этой серии, вы, вероятно, уже догадываетесь, что функцию из библиотеки можно подключить в файле . «bashrc», используя команду  source. Как результат, вызывать функцию можно будет прямо из командной строки.

Отредактируйте  «.bashrc», добавив в него такую строку (путь к файлу библиотеки в вашей системе, естественно, будет другим):

Теперь функцию можно вызывать прямо из командной строки:

Вызов функции из командной строки

Ещё приятнее то, что такая вот библиотека оказывается доступной всем дочерним процессам оболочки, то есть — ей можно пользоваться в bash-скриптах, не заботясь о подключении к ним этой библиотеки.

Тут стоит отметить, что для того, чтобы вышеприведённый пример заработал, может понадобиться выйти из системы, а потом войти снова. Кроме того, обратите внимание на то, что если имя функции из библиотеки совпадёт с именем какой-нибудь стандартной команды, вместо этой команды будет вызываться функция. Поэтому внимательно относитесь к именам функций.

https://habr.com/ru/company/ruvds/blog/327248/

Опубликовано вLinux

Ваш комментарий будет первым

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *