Сценарий:
$ cat t426.sh
set -x
f()
{
local x = "x"
eval $1=$x
}
x = "y"
f x
echo $x
$ bash t426.sh
+ x=y
+ f x
+ local x=x
+ eval x=x
++ x=x
+ echo y
y
Здесь мы видим, что y напечатано. Я ожидаю, что x будет напечатано.
Если я изменю имя локальной переменной с x на x_, то будет напечатано x.
Почему локальной переменной не присваивается нелокальная переменная с тем же именем?
Как исправить, чтобы локальная переменная имела то же имя, что и нелокальная переменная?
Вы определили локальную переменную с именем x. Зачем eval присваивать глобальную переменную с тем же именем? Тот факт, что значение $1 равно x, не означает, что $1 относится к глобальной переменной. Аргумент — это просто строка, а не какая-то ссылка.
f ведет себя так, как если бы его определение было где f () { local x = "x"; x=x; }.
какова основная цель? функция переопределяет значение глобальной переменной?
@markp-fuso Цель: в данном случае: функция переопределяет значение глобальной переменной; в общем случае: отдельный код возврата функции (например, статус операции: ОК/НОК) от фактического результата (действителен, если статус ОК) функции.
@chepner @choroba Действительно, в данном случае eval присваивается локальной переменной. Спасибо.
@pmor nameref будет обрабатывать переопределение значения глобальной переменной (пример см. в моем ответе); что касается отдельных кодов возврата... я не совсем понимаю/понимаю, чего вы хотите... вы имеете в виду f() выполнение разных команд (имя команды передается f())? для второго требования (коды возврата) я бы рекомендовал задать отдельный вопрос, обязательно предоставив несколько примеров того, чего вы пытаетесь выполнить.
local означает местный. Это особенность, а не ошибка (-;
@markp-fuso Re: «что вы хотите»: функция возвращает коды успеха/неудачи, возвращая любые другие данные через параметры «результат». См. 1 , 2 , 3.





Предположения:
f() вход — имя глобальной переменнойf() сбрасывает значение глобальной переменной (в этом случае всегда устанавливается строка 'x')С помощью bash 4.3+ у нас есть доступ к функции nameref, которая работает как символическая ссылка на (глобальную) переменную.
$ cat myscript
#!/bin/bash
f() {
declare -l -n _var=$1 # -n == nameref; -l == local (insures we don't clobber a global var named '_var'
_var = "x"
}
a=3
b = "y"
echo "### before:"
typeset -p a b
f a
f b
echo "### after:"
typeset -p a b
Решение проблемы OP — local variable has the same name as a non-local variable — вместо локальной переменной с постоянно меняющимся именем (чтобы соответствовать глобальной переменной) у вас есть локальная переменная со статическим именем (_var), которая действует как символическая ссылка на глобальную переменную.
Берем на тест-драйв:
$ ./myscript
### before:
declare -- a = "3"
declare -- b = "y"
### after:
declare -- a = "x"
declare -- b = "x"
Насколько вам известно, широко ли будет использоваться bash 4.3+ в 2024 году? Другими словами: насколько вероятно, что в 2024 году эта функция nameref не будет доступна?
@pmor 4.3 вышел примерно в 2014 году; Я использую Ubuntu 22.04, которая сейчас работает bash 5.1.16; Я ожидал, что все «основные» bash выпуски будут включать nameref поддержку, но могут быть и исключения; альтернативой nameref могут быть косвенные ссылки на переменные... выполнимо/работоспособно, но немного запутанно в использовании... веб-поиск должен выдать множество совпадений с использованием косвенных ссылок на переменные
Большим исключением является macOS, где обычный пользователь все еще использует bash 3.2, если только он не решил использовать zsh или не установил себе более новую версию bash. Не знаю точно, но согласен, что застревание на версии старше 4.3 будет скорее исключительным случаем в 2024 году.
Как вы узнаете, какая переменная (локальная или глобальная) используется? Локальные переменные маскируют глобальные.