Что такое косвенная экспансия? Что означает $ {! Var *}?

87

Я читаю « Руководство по Bash для начинающих ». Он говорит:

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

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

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

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

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

Как PARAMETERсправедливо !N*, то

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

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

Афон
источник

Ответы:

112

Если вы читаете 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
Paxdiablo
источник
1
Спасибо за ответ. Чем больше я читаю «Руководство по Bash для начинающих», тем больше спрашиваю себя, понимает ли автор то, что пишет.
LRDPRDX 02
24

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

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

$ NAME="VARIABLE"
$ VARIABLE=42
$ echo ${!NAME}
42
Кевин
источник
6
Вау, кто знал, что понять смысл жизни, вселенной и всего остального было так легко!
KomodoDave
3

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

echo ${!NP*}

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

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

:~> export myVar="hi"
:~> echo ${!my*}
    myVar
:~> export ${!my*}="bye"
:~> echo $myVar
    bye
tpg2114
источник
будут ли другие переменные, соответствующие моему *, также иметь значение «пока»?
Энтони
1
@Anthony Я попробовал, и если он ${!my*}расширяется до myA, myB, myA экспортируется с его текущим значением, а myB устанавливается на «пока» и экспортируется. Не очень полезно.
GKFX
3

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

Игнасио Васкес-Абрамс
источник
Так, кроме *случая, это то же самое, что и ${${VAR}}?
chronospoon
1
@chronospoon``, короче ${${VAR}}записываемый как ${$VAR}, недопустим, поскольку $VARвозвращает строку, которая не может следовать за $знаком; чтобы использовать строку в качестве имени переменной, вам нужно ввести один уровень косвенности (как указано в самом исходном вопросе), т.е. вы можете использовать ${!VAR}, что делает именно то, что вы ожидаете (ошибочно, но понятно) ${$VAR}.
Enlico
0

Вы можете обратиться к этому документу GNU для bash за авторитетной информацией.

https://www.gnu.org/software/bash/manual/html_node/Shell-Parameter-Expansion.html#Shell-Parameter-Expansion

Но в основном косвенное расширение не выполняется ${!prefix*} как одно из исключений, в вашем примере N - это префикс.

Документ объяснит, что такое косвенное расширение в bash.

Маргач Крис
источник