Форматирование строк PowerShell: почему символ двоеточия приводит к тому, что значение моей переменной остается пустым? - PullRequest
25 голосов
/ 05 декабря 2011

Я просматривал, что будет со следующими WinRM и PowerShell 3, просматривал список критических изменений и видел то, чего я никогда раньше не видел.

Пример был:

$server = "msp42"
$status = "online"
"$server: $status"

В результате получилось:

онлайн

Хорошо, я никогда не сталкивался с этим раньше и понятия не имею, почему двоеточие вызвало проблему.Решение, предложенное в документе, заключалось в том, чтобы поставить пробел (что глупо, потому что тогда вы меняете вывод):

"$server : $status"

Другое предложение заключалось в использовании этого формата (нового для меня!):

"${server}: $status"

Последнее предложение состояло в том, чтобы сделать выражение, с которым я знаком и все время использую:

"$($server): $status"

Итак, мои вопросы к вам, гуру PowerShell:

  1. Какого черта с этой толстой кишкой?Это делает что-то?

  2. Какого черта синтаксис ${variable}?Строго ли имеет дело с двоеточием или у него есть какие-то аккуратные особенности?

Ответы [ 2 ]

39 голосов
/ 05 декабря 2011

Двоеточие является допустимым символом для имен переменных, например, в $Env:PATH и т. д.

Вы также можете использовать следующую опцию

$server`: $status

или, в некоторых случаях, строка формата более читабельна:

'{0}: {1}' -f $server, $status

Вернуться к толстой кишке. Существует специальный случай для имен переменных, которые соответствуют элементу в PSDrive:

$Env:Foo           # equivalent to the contents of Env:\Foo
$Function:C:       # equivalent to the contents of Function:\C:
${C:\autoexec.bat} # ... you get the picture

Синтаксис ${} существует, чтобы иметь возможность указывать имена переменных, которые в противном случае используют символы, зарезервированные для других частей синтаксиса. Вы могли бы видеть, что он похож (но более мощный) на C # @ перед идентификаторами. См. Выше, где \ используется в имени переменной, поскольку $Drive:Item работает только для текущего контейнера на диске (или корня для неиерархических, таких как Env, Alias или Function).

Другой пример, где имя переменной обычно имеет неверный синтаксис:

PS> $+
The term '$+' is not recognized as the name of a cmdlet, function, script file, or operable program. Check the
spelling of the name, or if a path was included, verify that the path is correct and try again.
At line:1 char:1
+ $+
+ ~~
    + CategoryInfo          : ObjectNotFound: ($+:String) [], CommandNotFoundException
    + FullyQualifiedErrorId : CommandNotFoundException

PS> ${+} = 5
PS> ${+}
5
PS> Get-Variable +

Name                           Value
----                           -----
+                              5
9 голосов
/ 16 ноября 2015

Вот что-то, что споткнуло меня на днях в скрипте Windows PowerShell.Допустим, у вас есть переменные $ user и $ machine, и вы хотите напечатать строку со значением их обоих, разделенных двоеточием (':').

Очевидно, вы можете сделать это с помощью конкатенации строк.:

$user = 'tomasr' 
$machine = 'arcano' 

write ($user + ':' + $machine)

Это работает, но разве PowerShell не поддерживает эту замечательную функцию интерполяции строк?Да, да, это так!Так почему бы нам просто не переписать это так:

write "$user:$machine"

Но подождите!Если вы запустите эту последнюю строку, все, что вы получите, - это значение переменной $ machine ... куда ушел $ user?

Ответ заключается в том, что двоеточие имеет особое значение в именах переменных PowerShell: оно используетсясвязать переменную с определенной областью или пространством имен.В PowerShell есть несколько областей действия, таких как script и global;так, например, глобальная переменная может быть названа $ global: var.

Но разве мы не видели этот синтаксис где-либо еще?Конечно, как насчет $ env: PATH?То же самое;за исключением того, что env - это не самоцель, а PSDrive.Таким образом, часть перед ':' может быть либо фактической областью, определенной PS, либо PSDrive.Черт возьми, вы даже можете попробовать что-то вроде «$ {c: autoexec.bat}» и наблюдать, как происходит волшебство!

Так что проблема с нашей интерполяцией строк заключается в том, что когда PowerShell видит "$user:$machine", он ожидает найтиscope / psdrive с именем «user» и ожидает, что имя переменной будет следовать за «:», но «$» недопустимо, и «user» не является ни областью действия, ни PSDrive, что немного смущает PowerShell.Но так как он слишком джентльмен, он просто исправляет это настолько хорошо, насколько может, и игнорирует все до этого момента и просто сбрасывает $ machine без жалоб.Очень мило с его стороны, но это действительно может сбить вас с толку, если вы этого не ожидаете!

Можем ли мы избежать этого?Да, мы можем, просто разделив имена переменных точно для PowerShell, используя '{}', например:

write "${user}:$machine"

Раздел 5.8 на стр. 141 превосходного Windows PowerShell в действии Брюса Пайетта охватывает тему переменныхв PowerShell и дал мне подсказку, чтобы обойти эту проблему.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...