fi # "Абсолютное значение" переменной $return_val.
# -------------------------------------------------------------------------- #
if [ "$return_val" -eq "$E_NPARAM_ERR" ]
then # Признак ошибки в параметрах, при выходе из функции так же поменял знак.
echo "Ошибка: Недостаточно аргументов."
elif [ "$return_val" -eq "$EQUAL" ]
then
echo "Числа равны."
else
echo "Наиболшее число: $return_val."
fi
exit 0
См. также Пример A-8.
Упражнение:Используя только что полученные знания, добавьте в предыдущий пример, преобразования чисел в римскую форму записи, возможность обрабатывать большие числа.
Перенаправление
Перенаправление ввода для функций
Функции -- суть есть блок кода, а это означает, что устройство stdin для функций может быть переопределено (перенаправление stdin) (как в Пример 3-1).
Пример 22-7. Настоящее имя пользователя
#!/bin/bash
# По имени пользователя получить его "настоящее имя" из /etc/passwd.
ARGCOUNT=1 # Ожидается один аргумент.
E_WRONGARGS=65
file=/etc/passwd
pattern=$1
if [ $# -ne "$ARGCOUNT" ]
then
echo "Порядок использования: `basename $0` USERNAME"
exit $E_WRONGARGS
fi
file_excerpt () # Производит поиск в файле по заданному шаблону, выводит требуемую часть строки.
{
while read line
do
echo "$line" | grep $1 | awk -F":" '{ print $5 }' # Указывет awk использовать ":" как разделитель полей.
done
} <$file # Подменить stdin для функции.
file_excerpt $pattern
# Да, этот сценарий можно уменьшить до
# grep PATTERN /etc/passwd | awk -F":" '{ print $5 }'
# или
# awk -F: '/PATTERN/ {print $5}'
# или
# awk -F: '($1 == "username") { print $5 }'
# Однако, это было бы не так поучительно.
exit 0
Ниже приводится альтернативный, и возможно менее запутанный, способ перенаправления ввода для функций. Он заключается в использовании перенаправления ввода для блока кода, заключенного в фигурные скобки, в пределах функции.
# Вместо:
Function ()
{
...
} < file
# Попробуйте так:
Function ()
{
{
...
} < file
}
# Похожий вариант,
Function () # Тоже работает.
{
{
echo $*
} | tr a b
}
Function () # Этот вариант не работает.
{
echo $*
} | tr a b # Наличие вложенного блока кода -- обязательное условие.
# Спасибо S.C.
22.2. Локальные переменные
Что такое "локальная" переменная?
локальные переменные
Переменные, объявленные как локальные , имеют ограниченную область видимости, и доступны только в пределах блока, в котором они были объявлены. Для функций это означает, что локальная переменная "видна" только в теле самой функции.
Пример 22-8. Область видимости локальных переменных
#!/bin/bash
func ()
{
local loc_var=23 # Объявление локальной переменной.
echo
echo "\"loc_var\" в функции = $loc_var"
global_var=999 # Эта переменная не была объявлена локальной.
echo "\"global_var\" в функции = $global_var"
}
func
# Проверим, "видна" ли локальная переменная за пределами функции.
echo
echo "\"loc_var\" за пределами функции = $loc_var"
# "loc_var" за пределами функции =
# Итак, $loc_var не видна в глобальном контексте.
echo "\"global_var\" за пределами функции = $global_var"
# "global_var" за пределами функции = 999
# $global_var имеет глобальную область видимости.
echo
exit 0
Переменные, объявляемые в теле функции, считаются необъявленными до тех пор, пока функция не будет вызвана. Это касается всех переменных.
#!/bin/bash
func ()
{
global_var=37 # Эта переменная будет считаться необъявленной
#+ до тех пор, пока функция не будет вызвана.
} # КОНЕЦ ФУНКЦИИ
echo "global_var = $global_var" # global_var =
# Функция "func" еще не была вызвана,
#+ поэтому $global_var пока еще не "видна" здесь.
func
echo "global_var = $global_var" # global_var = 37
# Переменная была инициализирована в функции.
22.2.1. Локальные переменные делают возможной рекурсию.
Хотя локальные переменные и допускают рекурсию [ 52 ] Herbert Mayer определяет рекурсию, как "...описание алгоритма с помощью более простой версии того же самого алгоритма..." Рекурсивной называется функция, которая вызывает самого себя.
, но она сопряжена с большими накладными расходами и не рекомендуется для использования в сценариях [ 53 ] Слишком глубокая рекурсия может вызвать крах сценария. #!/bin/bash recursive_function () { (( $1 < $2 )) && recursive_function $(( $1 + 1 )) $2; # Увеличивать 1-й параметр до тех пор, #+ пока он не станет равным, или не превысит, второму параметру. } recursive_function 1 50000 # Глубина рекурсии = 50,000! # Само собой -- Segmentation fault. # Рекурсия такой глубины может "обрушить" даже программу, написанную на C, #+ по исчерпании памяти, выделенной под сегмент стека. # Спасибо S.C. exit 0 # Этот сценарий завершает работу не здесь, а в результате ошибки Segmentation fault.
.
Читать дальше