Когда ваши сценарии bash становятся все больше и больше, все может стать очень запутанным!
Вы можете снова и снова переписывать одни и те же фрагменты кода в разных частях ваших сценариев bash.
К счастью, вы можете избежать переписывания кода, используя функции в bash, которые сделают ваши скрипты более организованными и читаемыми.
В этой статье вы научитесь создавать функции, возвращать значения функций и передавать аргументы функций в сценариях оболочки bash.
Кроме того, вы узнаете, как работают области видимости переменных и как определять рекурсивные функции.
Есть два разных синтаксиса для объявления функций bash. Следующий синтаксис является наиболее часто используемым способом создания функций bash:
function_name () { commands }
Вторая менее часто используемая функция создания bash-функций начинается с зарезервированной рабочей функции, за которой следует имя функции, как показано ниже:
function function_name { commands }
Теперь есть пара вещей, о которых вы должны знать при работе с функциями:
Каждый раз, когда вы хотите, чтобы функция запускалась, вам просто нужно ее вызвать! Для вызова функции достаточно просто указать имя функции.
Взгляните на следующий сценарий bash fun.sh :
#!/bin/bash hello () { echo "Hello World" } hello hello hello
Мы определили функцию с именем hello, которая просто выводит на терминал строку «Hello World». Обратите внимание, что мы сделали три вызова функции hello, и поэтому, если вы запустите сценарий, вы увидите, что на экране трижды напечатана строка «Hello World»:
destroyer@andreyex:~$ ./fun.sh Hello World Hello World Hello World
Во многих языках программирования функции возвращают значение при вызове; однако это не относится к bash, поскольку функции bash не возвращают значения.
Когда функция bash завершает выполнение, она возвращает статус выхода последней выполненной команды, записанный в $? переменная. Ноль указывает на успешное выполнение или ненулевое положительное целое число (1-255) указывает на сбой.
Вы можете использовать оператор return, чтобы изменить статус выхода функции. Например, взгляните на следующий сценарий error.sh:
#! /bin/bash error () { blabla return 0 } error echo "Состояние возвращаемого значения ошибки функции: $?"
Если вы запустите bash-скрипт error.sh , вы можете быть удивлены результатом:
destroyer@andreyex:~$ ./error.sh ./error.sh: line 4: blabla: command not found Состояние возвращаемого значения ошибки функции: 0
Без оператора return 0 функция ошибки никогда бы не вернула ненулевой статус выхода, поскольку blabla приводит к ошибке команда не найдена .
Итак, как видите, хотя функции bash не возвращают значения, мы нашли обходной путь, изменив статусы выхода из функций.
Вы также должны знать, что оператор return немедленно завершает функцию.
Вы можете передавать аргументы функции так же, как вы можете передавать аргументы сценарию bash. Вы просто включаете аргументы при вызове функции.
Для демонстрации давайте взглянем на следующий сценарий bash iseven.sh :
#!/bin/bash iseven () { if [ $(($1 % 2)) -eq 0 ]; then echo "$1 is even." else echo "$1 is odd." fi } iseven 3 iseven 4 iseven 20 iseven 111
Функция iseven () проверяет, является ли число четным или нечетным. Мы сделали четыре вызова функций для iseven(). Для каждого вызова функции предоставили одно число, которое является первым дополнением к функции iseven() и на которое ссылается переменная $ 1 в определении функции.
Давайте запустим bash-скрипт iseven.sh, чтобы убедиться, что он работает:
destroyer@andreyex:~$ ./iseven.sh 3 is odd. 4 is even. 20 is even. 111 is odd.
Вы также должны понимать, что аргументы функции bash и аргументы сценария bash — это две разные вещи. Чтобы противопоставить разницу, взгляните на следующий сценарий bash funarg.sh :
#!/bin/bash fun () { echo "$1 is the first argument to fun()" echo "$2 is the second argument to fun()" } echo "$1 это первый аргумент к сценарию." echo "$2 это второй аргумент к сценарию." fun Yes 7
Запустите скрипт с парой аргументов и посмотрите на результат:
destroyer@andreyex:~$ ./funarg.sh Cool Stuff Cool это первый аргумент к сценарию. Stuff это второй аргумент к сценарию. Yes is the first argument to fun()7 is the second argument to fun()
Как видите, даже если вы использовали одни и те же переменные $ 1 и $ 2 для ссылки как на аргументы скрипта, так и на аргументы функции, они дают разные результаты при вызове из функции.
Переменные Bash могут иметь глобальную или локальную область видимости. Вы можете получить доступ к глобальной переменной в любом месте сценария bash независимо от области действия. Напротив, доступ к локальной переменной можно получить только из определения их функции.
Чтобы продемонстрировать это, взгляните на следующий сценарий bash scope.sh :
#!/bin/bash v1='A' v2='B' myfun() { local v1='C' v2='D' echo "Inside myfun(): v1: $v1, v2: $v2" } echo "Before calling myfun(): v1: $v1, v2: $v2" myfun echo "After calling myfun(): v1: $v1, v2: $v2"
Сначала мы определили две глобальные переменные v1 и v2 . Затем внутри определения myfun() мы использовали ключевое слово local для определения локальной переменной v1 и изменил глобальную переменную v2. Обратите внимание, что вы можете использовать одно и то же имя переменной для локальных переменных в разных функциях.
Теперь запустим скрипт:
destroyer@andreyex:~$ ./scope.sh Before calling myfun(): v1: A, v2: B Inside myfun(): v1: C, v2: D After calling myfun(): v1: A, v2: D
Из вывода скрипта можно сделать следующие выводы:
Рекурсивная функция — это функция, которая вызывает сама себя! Рекурсивные функции пригодятся, когда вы пытаетесь решить проблему программирования, которую можно разбить на более мелкие подзадачи.
Факторный функция является классическим примером рекурсивной функции. Взгляните на следующий сценарий bash factorial.sh:
#!/bin/bash factorial () { if [ $1 -le 1 ]; then echo 1 else last=$(factorial $(( $1 -1))) echo $(( $1 * last )) fi } echo -n "4! is: " factorial 4 echo -n "5! is: " factorial 5 echo -n "6! is: " factorial 6
Любая рекурсивная функция должна начинаться с базового случая, который обязательно должен завершать цепочку рекурсивных вызовов функций. В функции factorial() базовый случай определяется следующим образом:
if [ $1 -le 1 ]; then echo 1
Теперь выведите рекурсивный случай для факториальной функции. Чтобы вычислить факториал числа n, где n — положительное число больше единицы, вы можете умножить n на факториал n-1 :
factorial(n) = n * factorial(n-1)
Давайте воспользуемся приведенным выше уравнением, чтобы записать этот рекурсивный случай:
last=$(factorial $(( $1 -1))) echo $(( $1 * last ))
Теперь запустите скрипт и убедитесь, что получили правильные результаты:
destroyer@andreyex:~$ ./factorial.sh 4! is: 24 5! is: 120 6! is: 720
В качестве дополнительного упражнения попробуйте написать рекурсивную функцию для вычисления n-го числа Фибоначчи. Сначала попробуйте придумать базовый случай, а затем рекурсивный.
Потрясающие! Надеюсь, вам понравилось создавать функции в bash!