Почему локальной переменной не присваивается нелокальная переменная с тем же именем?

Сценарий:

$ 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.

Почему локальной переменной не присваивается нелокальная переменная с тем же именем?

Как исправить, чтобы локальная переменная имела то же имя, что и нелокальная переменная?

Как вы узнаете, какая переменная (локальная или глобальная) используется? Локальные переменные маскируют глобальные.

choroba 28.08.2024 17:33

Вы определили локальную переменную с именем x. Зачем eval присваивать глобальную переменную с тем же именем? Тот факт, что значение $1 равно x, не означает, что $1 относится к глобальной переменной. Аргумент — это просто строка, а не какая-то ссылка.

chepner 28.08.2024 17:42
f ведет себя так, как если бы его определение было где f () { local x = "x"; x=x; }.
chepner 28.08.2024 17:43

какова основная цель? функция переопределяет значение глобальной переменной?

markp-fuso 28.08.2024 17:54

@markp-fuso Цель: в данном случае: функция переопределяет значение глобальной переменной; в общем случае: отдельный код возврата функции (например, статус операции: ОК/НОК) от фактического результата (действителен, если статус ОК) функции.

pmor 28.08.2024 18:20

@chepner @choroba Действительно, в данном случае eval присваивается локальной переменной. Спасибо.

pmor 28.08.2024 18:22

@pmor nameref будет обрабатывать переопределение значения глобальной переменной (пример см. в моем ответе); что касается отдельных кодов возврата... я не совсем понимаю/понимаю, чего вы хотите... вы имеете в виду f() выполнение разных команд (имя команды передается f())? для второго требования (коды возврата) я бы рекомендовал задать отдельный вопрос, обязательно предоставив несколько примеров того, чего вы пытаетесь выполнить.

markp-fuso 28.08.2024 18:25
local означает местный. Это особенность, а не ошибка (-;
shellter 28.08.2024 19:54

@markp-fuso Re: «что вы хотите»: функция возвращает коды успеха/неудачи, возвращая любые другие данные через параметры «результат». См. 1 , 2 , 3.

pmor 28.08.2024 21:32
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
1
10
50
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Предположения:

  • 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 28.08.2024 18:24

@pmor 4.3 вышел примерно в 2014 году; Я использую Ubuntu 22.04, которая сейчас работает bash 5.1.16; Я ожидал, что все «основные» bash выпуски будут включать nameref поддержку, но могут быть и исключения; альтернативой nameref могут быть косвенные ссылки на переменные... выполнимо/работоспособно, но немного запутанно в использовании... веб-поиск должен выдать множество совпадений с использованием косвенных ссылок на переменные

markp-fuso 28.08.2024 18:30

Большим исключением является macOS, где обычный пользователь все еще использует bash 3.2, если только он не решил использовать zsh или не установил себе более новую версию bash. Не знаю точно, но согласен, что застревание на версии старше 4.3 будет скорее исключительным случаем в 2024 году.

chepner 28.08.2024 21:15

Другие вопросы по теме