Подтвердить что ты не робот

Форматирование строк PowerShell: почему символ двоеточия, заставляющий мое значение переменной быть пустым?

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

Пример:

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

Результирующий результат:

онлайн

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

"$server : $status"

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

"${server}: $status"

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

"$($server): $status"

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

  • Какая черта с этой двоеточием? Это сделать что-то?

  • Что такое синтаксис ${variable}? Это строго для борьбы с двоеточием или у него есть некоторые опрятные функции?

4b9b3361

Ответ 1

Двойник является допустимым символом для имен переменных, например. в $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

Синтаксис ${} существует, чтобы иметь возможность указывать имена переменных, которые в противном случае используют символы, зарезервированные для других частей синтаксиса. Вы могли видеть, что это похоже (но более мощное) на С# @ перед идентификаторами. См. Выше, где a \ используется в имени переменной, так как $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

Ответ 2

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

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

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

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

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

write "$user:$machine"

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

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

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

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

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

write "${user}:$machine"

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