Назначение переменной в родительском контексте в Bash

Я хочу написать функцию, аналогичную встроенной read, где я передаю имя переменной в качестве аргумента, а функция возвращает свой результат в названную переменную.

Я пытался сделать это так:

GLOBAL_VAR=0

foo() {
    local var="$1"; shift
    local result

    # ...

    (( GLOBAL_VAR++ ))

    # ...

    eval "${var}=\${result}"
}

Однако есть проблема с вышеизложенным: вышеописанное не работает, если я вызываю foo с первым аргументом var или result, потому что тогда присваивается локальная переменная, определенная внутри foo, а не ее вызывающая сторона. По сути, это приводит к утечке реализации foo.

Если вместо этого я использую nameref (local -n), запуск foo var приводит к предупреждающему сообщению, а foo result ничего не возвращает вызывающему, потому что переменная result присваивается внутри функции. И я не могу просто переименовать переменную во что-то, что не будет конфликтовать, потому что я на самом деле намереваюсь выполнить здесь рекурсию, поэтому переменная неизбежно будет конфликтовать сама с собой. Namerefs вообще не помогают в моей проблеме.

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

Есть ли способ назначить переменную с динамическим именем, как определено в контексте вызывающего объекта?

(Другими словами, я ищу bash-эквивалент Tcl upvar< /а>.)


person user3840170    schedule 05.05.2020    source источник
comment
Отвечает ли это на ваш вопрос? Передача аргументов по ссылке   -  person KamilCuk    schedule 05.05.2020
comment
В функциях declare делает переменные локальными, поэтому я не могу это использовать. И связанный ответ не помогает решить проблему в этом вопросе: его использование приводит к environment: warning: var: circular name reference.   -  person user3840170    schedule 05.05.2020
comment
declare makes variables local при использовании без конкретных аргументов — да. Почему это имеет значение? environment: warning: var: circular name reference и нет никакого возможного решения этой проблемы. Итак, declare -n _pIcK_uNiQuE_NaMe_FoR_nAmE_rEfErEnCe="$1"   -  person KamilCuk    schedule 05.05.2020
comment
@ user3840170: Вы не ответили на комментарий выше. Почему имя ссылочной переменной в функции вообще имеет значение?   -  person Inian    schedule 05.05.2020
comment
Вопрос с самого начала был один и тот же: как изменить переменную в вызывающем объекте функции, не раскрывая деталей реализации функции. Не обращайте внимания на declare, на самом деле это не проблема; проблема в том, что namerefs указывают на переменные в контексте функции, а не на ее вызывающую сторону, как я хотел.   -  person user3840170    schedule 05.05.2020
comment
@ user3840170: Я не уверен, что в bash есть простой способ сделать это. Удачи в отрицании ответов и попытках найти ответ   -  person Inian    schedule 05.05.2020
comment
Связано: Циклические ссылки на имена в оболочке bash функция, но не в ksh. Я думал, что Bash 5 должен был это исправить, но, как показывает ответ Кусалананды, он действительно не справляется с этим.   -  person ilkkachu    schedule 02.03.2021


Ответы (1)


Я подозреваю, что вы получите что-то вроде:

foo() {
    local result
    result="some computation with $1"
    echo "$result"
}

thing=$(set -eu; foo)
person dstromberg    schedule 05.05.2020
comment
Я специально сказал, что не хочу использовать подоболочку. - person user3840170; 05.05.2020