ti-enxame.com

Formatação de seqüência de caracteres do PowerShell: Por que o caractere de dois pontos faz com que o valor da minha variável fique em branco?

Eu estava olhando o que viria com o próximo WinRM e PowerShell 3 e estava olhando a lista de alterações mais recentes e vi algo que nunca tinha visto antes.

O exemplo foi:

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

A saída resultante foi:

conectados

OK, eu nunca tinha encontrado isso antes e não tenho idéia do por que o cólon causou um problema. Uma solução sugerida no documento foi colocar um espaço (que é bobo porque você altera a saída):

"$server : $status"

Outra sugestão foi usar este formato (novo para mim!):

"${server}: $status"

A sugestão final foi fazer uma expressão com a qual estou familiarizado e uso o tempo todo:

"$($server): $status"

Portanto, minhas perguntas para os gurus do PowerShell são:

  1. O que diabos está acontecendo com esse cólon? faz alguma coisa?

  2. O que diabos é o ${variable} sintaxe? É estritamente para lidar com o cólon ou possui alguns recursos interessantes?

30
Kevin Buchan

Os dois pontos são um caractere válido para nomes de variáveis, por exemplo no $Env:PATH, etc.

Você também pode usar a seguinte opção

$server`: $status

ou, em alguns casos, uma string de formato é mais legível:

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

De volta ao cólon. Há um caso especial para nomes de variáveis ​​que correspondem a um item em um 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 sintaxe ${} existe para poder especificar nomes de variáveis ​​que usam caracteres reservados para outras partes da sintaxe. Você pode vê-lo como sendo semelhante (mas mais poderoso) aos C # @ na frente dos identificadores. Veja acima onde um \ é usado no nome da variável, pois $Drive:Item funciona apenas para o contêiner atual em uma unidade (ou a raiz para contêineres não hierárquicos como Env, Alias ou Function).

Outro exemplo em que o nome da variável seria normalmente sintaxe inválida:

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
41
Joey

Aqui está algo que me tropeçou no outro dia em um script do Windows PowerShell. Digamos que você precise das variáveis ​​$ user e $ machine e deseje imprimir uma string com o valor de ambos separados por dois pontos (':').

Obviamente, você pode fazer isso usando a concatenação de strings:

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

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

Isso funciona, mas o PowerShell não suporta esse recurso de interpolação de seqüência de caracteres Nice? Porque sim! Então, por que não reescrevemos assim:

write "$user:$machine"

Mas espere! Se você executar essa última linha, tudo o que você obtém é o valor da variável $ machine ... para onde $ user foi?

A resposta é que os dois pontos têm um significado especial nos nomes de variáveis ​​do PowerShell: é usado para associar a variável a um escopo ou espaço de nome específico. Existem alguns escopos definidos pelo PowerShell, como script e global; portanto, por exemplo, uma variável global pode ter o nome $ global: var.

Mas também não vimos essa sintaxe em outro lugar? Claro, que tal $ env: PATH? Mesma coisa; exceto aqui env não é um escopo por si só, mas um PSDrive. Portanto, a parte anterior ao ':' pode ser um escopo real definido pelo PS ou um PSDrive. Heck, você pode até tentar algo como "$ {c: autoexec.bat}" e assistir a mágica acontecer!

Portanto, o problema com nossa interpolação de strings é que, quando o PowerShell vê "$user:$machine", espera encontrar um escopo/psdrive chamado 'user' e espera que um nome de variável siga o ':', mas '$' não é válido e 'user' não é um escopo ou PSDrive, o que confunde um pouco o PowerShell. Mas, como ele é um cavalheiro demais, ele apenas corrige o melhor que pode e ignora tudo até esse ponto e apenas despeja $ machine sem reclamar. Legal da parte dele, mas pode realmente te enganar, se você não espera!

Podemos evitar isso? Sim, podemos simplesmente delimitar nomes de variáveis ​​exatamente para o PowerShell usando '{}', assim:

write "${user}:$machine"

A Seção 5.8 na página 141 do excelente Windows PowerShell in Action de Bruce Payette aborda o tópico de variáveis ​​no PowerShell e me deu a pista para contornar esse problema.

9
Vinay