Что такое косвенное расширение? Что означает ${! Var *}?

Я читаю "Bash Guide for Beginners". В нем говорится:

Если первый символ PARAMETER является восклицательным знаком, Bash использует значение переменной, сформированной из остальной части PARAMETER, как имя переменной; эта переменная затем расширяется и это значение используется в остальной части подстановки, а не как значение PARAMETER. Это называется косвенным расширением.

Приведенный пример:

franky ~> echo ${!N*}
NNTPPORT NNTPSERVER NPX_PLUGIN_PATH

Я не совсем понимаю здесь:

значение переменной, сформированной из остальной части PARAMETER

Поскольку PARAMETER является просто !N*, тогда

остальная часть PARAMETER

является просто N*. Как это могло образовать переменную? Выбрали ли Bash всю возможную команду?

Ответы

Ответ 1

Если вы читаете справочную страницу bash, это в основном подтверждает то, что вы заявили:

Если первым символом параметра является восклицательный знак (!), вводится уровень переменной косвенности. Bash использует значение переменной, сформированной из остальной части параметра, как имя переменной; эта переменная затем расширяется и это значение используется в остальной части подстановки, а не значение самого параметра. Это называется косвенным расширением.

Однако, прочитав оттуда:

Исключение составляют разложения ${!prefix*} и ${!name[@]}, описанные ниже.

${!prefix*} Соответствующий префикс имен. Расширяется до имен переменных, имена которых начинаются с префикса, разделенные первым символом специальной переменной IFS.

Другими словами, ваш конкретный пример ${!N*} является исключением из правила, которое вы указали. Однако он работает так, как рекламируется в ожидаемых случаях, например:

$ export xyzzy=plugh ; export plugh=cave

$ echo ${xyzzy}  # normal, xyzzy to plugh
plugh

$ echo ${!xyzzy} # indirection, xyzzy to plugh to cave
cave

Ответ 2

Как представляется, существует исключение, когда данная "косвенность" заканчивается на *, как здесь. В этом случае все имена переменных начинаются с указанной вами части (N здесь). Bash может сделать это, потому что он отслеживает переменные и знает, какие из них существуют.

Истинная косвенность такова:
Скажем, у меня есть переменная $VARIABLE, установленная на 42, и у меня есть другая переменная $NAME, установленная на VARIABLE. ${!NAME} даст мне 42. Вы используете значение одной переменной, чтобы указать имя другого:

$ NAME="VARIABLE"
$ VARIABLE=42
$ echo ${!NAME}
42

Ответ 3

Да, он ищет все возможные расширения переменных после!. Если вы сделали:

echo ${!NP*}

вы получите только NPX_PLUGIN_PATH.

Рассмотрим следующий пример:

:~> export myVar="hi"
:~> echo ${!my*}
    myVar
:~> export ${!my*}="bye"
:~> echo $myVar
    bye

Ответ 4

Вы попали в исключение в обработке косвенности, где, если последний символ *, будут возвращены все переменные, у которых есть префикс, указанный выше.