Поиск по сайту:

Понимание и написание функций в сценариях оболочки. Часть VI


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

Что такое функции?

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

Например, рассмотрим случай, когда нам нужно найти факториал числа на нескольких этапах конкретной программы. Вместо того, чтобы каждый раз писать весь код (для вычисления факториала), мы можем написать ту часть кода, которая вычисляет факториал один раз внутри блока и повторно использовать его несколько раз.

Зачем мы пишем функции?

  1. Это помогает нам повторно использовать код.
  2. Улучшите читабельность программы.
  3. Эффективное использование переменных внутри программы.
  4. Позволяет нам протестировать программу по частям.
  5. Отображает программу в виде набора подэтапов.
Функции в сценариях оболочки

Общий синтаксис написания функций в сценарии оболочки включает следующие способы.

function func_name {
	. . .
	commands
	. . .
}

or

func_name ( ) {
	. . .
	commands
	. . .
}

Opening curly braces can also be used in the second line as well.

func_name ( )
{
	. . .
	commands
	. . .
}

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

#!/bin/bash

call_echo ( ) {
	echo ‘This is inside function’
}

op=$1

if [ $# -ne 1 ]; then
	echo "Usage: $0 <1/0>"
else
	if [ $1 = 0 ] ; then
		echo ‘This is outside function’
	elif [ $1 = 1 ] ; then
		call_echo
	else
		echo ‘Invalid argument’
	fi
fi

exit 0

Определение функции должно предшествовать первому ее вызову. Нет ничего лучше «объявления функции» перед ее вызовом. И мы всегда можем вкладывать функции внутрь функций.

Примечание. Написание пустых функций всегда приводит к синтаксическим ошибкам.

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

#!/bin/bash

func_same ( ) {
	echo ‘First definition’
}

func_same ( ) {
	echo ‘Second definition’
}

func_same

exit 0
Функции, принимающие параметры и возвращающие значения

Давайте углубимся и рассмотрим функции, принимающие параметры и возвращающие значения. Чтобы вернуть значение из функции, мы используем встроенную оболочку return. Синтаксис следующий.

func_name ( ) {
	. . .
	commands
	. . .
	return $ret_val
}

Аналогично мы можем передавать аргументы функциям, разделенные пробелами, как показано ниже.

func_name $arg_1 $arg_2 $arg_3

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

#!/bin/bash

USG_ERR=7

max_two ( ) {
	if [ "$1" -eq "$2" ] ; then
		echo 'Equal'
		exit 0
	elif [ "$1" -gt "$2" ] ; then
		echo $1
	else
		echo $2
	fi
}

err_str ( ) {
	echo "Usage: $0 <number1>  <number2>"
	exit $USG_ERR
}

NUM_1=$1
NUM_2=$2
x
if [ $# -ne 2 ] ; then
	err_str
elif [ `expr $NUM_1 : '[0-9]*'` -eq ${#NUM_1} ] ; then
	if [ `expr $NUM_2 : '[0-9]*'` -eq ${#NUM_2} ] ; then  
		max_two $NUM_1 $NUM_2
	else
		err_str
	fi
else
	err_str
fi

exit 0

Вышеупомянутое выглядит немного сложным, но если мы прочитаем строки, все будет просто. Первые вложенные строки if-else if для целей проверки, т. е. для проверки количества и типа аргументов с помощью регулярных выражений. После этого мы вызываем функцию с двумя аргументами командной строки и выводим туда сам результат. Это связано с тем, что мы не можем возвращать из функции большие целые числа. Другой способ обойти эту проблему — использовать глобальные переменные для хранения результата внутри функции. Сценарий ниже объясняет этот метод.

#!/bin/bash

USG_ERR=7
ret_val=

max_two ( ) {
	if [ "$1" -eq "$2" ] ; then
		echo 'Equal'
		exit 0
	elif [ "$1" -gt "$2" ] ; then
		ret_val=$1
	else
		ret_val=$2
	fi
}

err_str ( ) {
	echo "Usage: $0 <number1>  <number2>"
	exit $USG_ERR
}

NUM_1=$1
NUM_2=$2

if [ $# -ne 2 ] ; then
	err_str
elif [ `expr $NUM_1 : '[0-9]*'` -eq ${#NUM_1} ] ; then
	if [ `expr $NUM_2 : '[0-9]*'` -eq ${#NUM_2} ] ; then  
		max_two $NUM_1 $NUM_2
		echo $ret_val
	else
		err_str
	fi
else
	err_str
fi

exit 0

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

  1. Основные советы по языку сценариев оболочки Linux. Часть I.
  2. 5 сценариев оболочки для новичков в Linux для изучения программирования оболочки – часть II
  3. Путешествуя по миру сценариев BASH для Linux – часть III
  4. Математический аспект программирования оболочки Linux. Часть IV.
  5. Вычисление математических выражений на языке сценариев Shell – Часть V

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