Практическое написание сценариев командной оболочки Bash/Эмуляция ссылочной адресации: различия между версиями

Содержимое удалено Содержимое добавлено
 
Строка 248:
 
== Ссылки на функции ==
 
Если пойти дальше, то и на функции можно делать ссылки. Выше мы убедились, что если переменная раскрывается не как аргумент команды или значение для присваивания, то интерпретатор пытается использовать раскрытое значение как имя команды. Ниже показан пример, как через ссылку вызываются разные функции. Самое сложное во всем этом — это инициализация ссылки именами функций в нужный момент. Мы немного упростим себе задачу и будем адресовать функции, которые имеют в своем имени одинаковое начало.
 
<source lang=bash>
#!/bin/bash
 
# Эта функция будет печатать аргументы вызываемой по ссылке функции.
# Функция использует переменную окружения MY_NAME, в которой она ожидает
# имя вызываемой функции. Кроме того, функция печатает переменную окружения,
# которая передается вызываемой по ссылке функции.
arg_printer() {
local -i counter
echo "--> Start trace -->"
echo " Called: $MY_NAME"
for arg; do
echo " ARGV[$((counter++))]: $arg"
done
echo " Environment: $(env | grep -oE "EXPORT=.*")"
echo "<-- End trace <--"
}
 
# Функции, которые мы будем вызывать по ссылке.
######################################################
mfunc_1() {
MY_NAME="$FUNCNAME" arg_printer "$@"
}
 
mfunc_2() {
MY_NAME="$FUNCNAME" arg_printer "$@"
}
 
mfunc_3() {
MY_NAME="$FUNCNAME" arg_printer "$@"
}
######################################################
 
# Далее мы вызываем функции по ссылке FREF в цикле. Заготовить список для цикла
# мы можем разными путями, но во всех случаях мы пользуемся тем, что имена функций
# начинаются на mfunc_
 
PREFIX='mfunc_'
 
echo "=== FIRST APPROACH ==="
 
# Здесь список функций подготавливается через общий префикс и скобочную подстановку.
for FREF in ${PREFIX}{1..3}; do
EXPORT="FREF:$FREF;" "${FREF}" a b c # Сам вызов прост: мы просто раскрываем ссылку как обычную переменную
# Обратите внимание, что перед вызовом по ссылке мы передаем экспортированную переменную EXPORT (см. в главе Команды),
# а также передаем несколько аргументов самой функции для печати.
done
 
echo "=== SECOND APPROACH ==="
 
# Здесь список формируется немного сложнее. Мы используем команду Bash compgen, которая
# при данной опции возвращает список всех объявленных на текущий момент функций. Далее мы фильтруем
# этот список утилитой grep.
for FREF in $(compgen -A function | grep "$PREFIX.*"); do
EXPORT="FREF:$FREF;" "${FREF}" a b c # Вызов абсолютной такой же как и в первом подходе.
done
</source>
Результат работы сценария
<source lang=bash>
=== FIRST APPROACH ===
--> Start trace -->
Called: mfunc_1
ARGV[0]: a
ARGV[1]: b
ARGV[2]: c
Environment: EXPORT=FREF:mfunc_1;
<-- End trace <--
--> Start trace -->
Called: mfunc_2
ARGV[0]: a
ARGV[1]: b
ARGV[2]: c
Environment: EXPORT=FREF:mfunc_2;
<-- End trace <--
--> Start trace -->
Called: mfunc_3
ARGV[0]: a
ARGV[1]: b
ARGV[2]: c
Environment: EXPORT=FREF:mfunc_3;
<-- End trace <--
=== SECOND APPROACH ===
--> Start trace -->
Called: mfunc_1
ARGV[0]: a
ARGV[1]: b
ARGV[2]: c
Environment: EXPORT=FREF:mfunc_1;
<-- End trace <--
--> Start trace -->
Called: mfunc_2
ARGV[0]: a
ARGV[1]: b
ARGV[2]: c
Environment: EXPORT=FREF:mfunc_2;
<-- End trace <--
--> Start trace -->
Called: mfunc_3
ARGV[0]: a
ARGV[1]: b
ARGV[2]: c
Environment: EXPORT=FREF:mfunc_3;
<-- End trace <--
</source>
 
Такие приемы обычно пригождаются при разработке черновых шаблонов новых приложений на языках подобных Си, например для демонстраций или моделирования алгоритмов.
 
== Косвенная адресация средствами Bash ==