Создание nameref регулярной переменной в bash
РЕДАКТИРОВАТЬ: Это было подтверждено как ошибка и будет исправлено: https://lists.gnu.org/archive/html/bug-bash/2018-03/msg00055.html
Так что я возиться с функцией косвенного обращения bash, namerefs. Я подумала, что поняла это, но потом наткнулась на то, что смутило меня, когда я пыталась понять, как сделать namerefs обычными переменными.
Вот соответствующий отрывок из man bash
:
declare -n
Присвойте каждому имени атрибут nameref, сделав ссылку на имя другой переменной. Эта другая переменная определяется значением name. Все ссылки, присвоения и модификации атрибутов name, кроме тех, которые используют или изменяют сам атрибут -n, выполняются в переменной, на которую ссылается значение name.
Часть я понимаю
Скажем, вы хотели сбросить nameref- не varaible, на который он указывает, а саму переменную. Вы не могли бы просто сказать unset foo
потому что это на самом деле может привести к foo
указывает на; вместо этого вы должны сделать его обычной переменной, а затем сбросить ее:
$ declare -p
$ foo=bar; bar='hello world'
$ declare -p
declare -- foo="bar"
declare -- bar="hello world"
$ declare -n foo; declare -p # 'foo' is now a nameref
declare -n foo="bar"
declare -- bar="hello world"
$ declare +n foo; declare -p # 'foo' is no longer a nameref
declare -- foo="bar"
declare -- bar="hello world"
$ unset foo; declare -p # 'foo' is unset, not bar
declare -- bar="hello world"
Часть я не понимаю
Это все имеет смысл для меня и согласуется с моим прочтением приведенного выше руководства. Что меня смущает, так это то, что происходит при незначительном изменении в вышесказанном, а именно: bar
неустановленный и необъявленный:
...
$ declare -p
declare -n foo="bar"
$ echo "${foo}" # These two commands behave as expected--i.e., identically to how namerefs usually behave, just with an unset variable.
-bash: foo: unbound variable
$ echo "${!foo}"
bar
$ declare +n foo; declare -p # Should make 'foo' a regular variable, right? Nope.
declare -n foo="bar" # Still a nameref--wtf?
declare -- bar # And now bar's back--unset still, but declared. Wtf??
$ declare +n foo; declare -p # THIS, however, works like I thought it would--but *why*? In both cases 'bar' is unset...
declare -- foo="bar"
declare -- bar
Я, очевидно, неправильно понимаю, как namerefs должны работать. Исходя из отрывка из man, я бы подумал, что сброс атрибута nameref foo
должен работать на foo
независимо от того, является ли его целью, bar
не объявлен.
Обратите внимание, что это работает так, как я думал, когда bar
не установлен, но объявлен. Это самая странная часть для меня - я не осознавал, что было какое-то значение для незадекларированной переменной! test -v
, ${var-_}
, ${var+_}
, а также set -u
кажется, что все заботятся о том, установлена ли переменная, и не делают различий между (A) неустановленной, необъявленной переменной и (B) неустановленной, объявленной переменной.
Может кто-нибудь объяснить, что здесь происходит, возможно, указать на ту часть руководства, которая объясняет это? Есть ли другие особые случаи в поведении имен, которые я собираюсь запутать? Спасибо!
Потенциально актуальная информация:
$ bash --version
GNU bash, version 4.4.19(1)-release (x86_64-unknown-linux-gnu)
...
$ echo "$-"
himuBCHs
Обратите внимание, что поведение сохраняется без set -u
; Я просто сделал это, чтобы сообщения bash стали немного понятнее.
1 ответ
Там новый аргумент unset
явно с целью отмены определения nameref (в отличие от переменной, на которую он указывает):
unset -n namevar