Функция, распознающая вызывающую сторону в bash

Функция, распознающая вызывающую сторону в bash

У меня есть функция (=callee), которая должна эффективно объявлять и назначать пару переменных в своем вызывающем. Она также должна уметь определять имя своего вызывающего.

На данный момент я достигаю первого, возвращая запись в переданную переменную строки, которая будет evalотредактирована вызывающей стороной.

 write_local_var_assignments variable_name; eval "$variable_name"

Я полагаю, что последнего можно достичь, либо заставив вызывающую функцию передать функцию "$FUNCNAME", либо заставив вызываемую функцию вызвать callerвстроенную функцию и проанализировать ее вывод.

Все эти решения кажутся очень неуклюжими, поэтому у меня два вопроса:

  1. Может ли вызываемый объект назначить локальные переменные в контексте вызывающего объекта без его содействия?

Т.е., могу ли я сжать:

 write_local_var_assignments variable_name; eval "$variable_name"

в просто

 run_local_var_assignments

?

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

решение1

В bashksh88, mksh, yash, dash, zsh) область действия локальной переменной является динамической.

Этот код:

f() { a=2; echo "f: $a"; }
g() { local a=1; f; echo "g: $a"; }
a=0
g
echo "global: $a"

выдает следующий результат:

f: 2
g: 2
global: 0

Это переменная updates , fпоскольку она вызывается из .g$ag

Это контрастирует с переменными, объявленными с typesetпомощью функций, объявленных с помощью kshсинтаксиса ( function f { ...; }) в ksh93, или переменными, объявленными с помощью private, zshгде вы получите:

f: 2
g: 1
global: 2

Так что в этом случае вам не нужно ничего делать.

Чтобы узнать имя вызывающей вас функции, в bash, вы можете использовать${FUNCNAME[1]}.

Эквивалент :zsh$funcstack[2]

$ zsh -c 'f() { echo $funcstack[2]; }; g() { f; }; g'
g
$ bash -c 'f() { echo "${FUNCNAME[1]}"; }; g() { f; }; g'
g

решение2

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

$(run_local_var_assignments)

Функция выглядит так:

emit () {
  local IFS=$'\n'
  printf 'eval eval %q' "$*"
}

Он выдает оператор eval, очень похожий на ваш eval "$variable_name"вышеприведенный. Поскольку это первое, что есть в результирующей строке, bash запускает выданный eval как команду.

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

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

run_local_var_assignments () {
  local assignments=()
  assignments+=( 'local myvar1="my value1"' )
  assignments+=( 'local myvar2="my value2"' )
  emit "${assignments[@]}"
}

Задания записываются так, как если бы они были исходным кодом, поэтому такие вещи, как пробелы в значениях, требуют кавычек, как указано выше.

Вызов этой функции в подстановке команды (как в начале этого ответа) создаст эти локальные переменные в области действия вызывающего объекта с этими значениями.

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

Связанный контент