Tudo o que você queria saber sobre substituição de variáveis em strings

Há muitas maneiras de usar variáveis em cadeias de caracteres. Estou chamando essa variável de substituição, mas estou me referindo a sempre que você quiser formatar uma cadeia de caracteres para incluir valores de variáveis. Isso é algo que muitas vezes me pego explicando para novos scripters.

Nota

A versão original deste artigo apareceu no blog escrito por @KevinMarquette. A equipe do PowerShell agradece Kevin por compartilhar esse conteúdo conosco. Por favor, confira seu blog em PowerShellExplained.com.

Concatenação

A primeira classe de métodos pode ser referida como concatenação. É basicamente pegar várias cordas e juntá-las. Há uma longa história de uso de concatenação para criar cadeias de caracteres formatadas.

$name = 'Kevin Marquette'
$message = 'Hello, ' + $name

A concatenação funciona bem quando há apenas alguns valores para adicionar. Mas isso pode se complicar rapidamente.

$first = 'Kevin'
$last = 'Marquette'
$message = 'Hello, ' + $first + ' ' + $last + '.'

Este exemplo simples já está ficando mais difícil de ler.

Substituição variável

O PowerShell tem outra opção mais fácil. Você pode especificar suas variáveis diretamente nas cadeias de caracteres.

$message = "Hello, $first $last."

O tipo de aspas que você usa ao redor da string faz a diferença. Uma cadeia de aspas duplas permite a substituição, mas uma única cadeia de aspas não. Há momentos em que você quer um ou outro, então você tem uma opção.

Substituição de comandos

As coisas ficam um pouco complicadas quando você começa a tentar obter os valores das propriedades em uma cadeia de caracteres. É aqui que muitas pessoas novas são tropeçadas. Primeiro deixe-me mostrar-lhe o que eles acham que deve funcionar (e ao pé da letra quase parece que deveria).

$directory = Get-Item 'c:\windows'
$message = "Time: $directory.CreationTime"

Você estaria esperando para obter o CreationTime$directoryfora do , mas em vez disso, você recebe isso Time: c:\windows.CreationTime como seu valor. A razão é que este tipo de substituição só vê a variável base. Ele considera o período como parte da cadeia de caracteres, então ele para de resolver o valor mais profundamente.

Acontece que esse objeto fornece uma cadeia de caracteres como um valor padrão quando colocado em uma cadeia de caracteres. Em vez disso, alguns objetos dão o nome do tipo, como System.Collections.Hashtable. Apenas algo a observar.

O PowerShell permite que você execute comandos dentro da cadeia de caracteres com uma sintaxe especial. Isso nos permite obter as propriedades desses objetos e executar qualquer outro comando para obter um valor.

$message = "Time: $($directory.CreationTime)"

Isso funciona muito bem para algumas situações, mas pode ficar tão louco quanto concatenação se você tiver apenas algumas variáveis.

Execução de comando

Você pode executar comandos dentro de uma cadeia de caracteres. Apesar de ter essa opção, não gosto. Ele fica confuso rapidamente e difícil de depurar. Eu executo o comando e salvo em uma variável ou uso uma cadeia de caracteres de formato.

$message = "Date: $(Get-Date)"

Formatar cadeia de caracteres

O .NET tem uma maneira de formatar cadeias de caracteres com as quais acho bastante fácil trabalhar. Primeiro, deixe-me mostrar o método estático para ele antes de mostrar o atalho do PowerShell para fazer a mesma coisa.

# .NET string format string
[string]::Format('Hello, {0} {1}.',$first,$last)

# PowerShell format string
'Hello, {0} {1}.' -f $first, $last

O que está acontecendo aqui é que a string é analisada para os tokens {0} e {1}, em seguida, usa esse número para escolher entre os valores fornecidos. Se você quiser repetir um valor em algum lugar na cadeia de caracteres, poderá reutilizar esse número de valores.

Quanto mais complicada a cadeia de caracteres fica, mais valor você obtém dessa abordagem.

Formatar valores como matrizes

Se a linha de formato ficar muito longa, você pode colocar seus valores em uma matriz primeiro.

$values = @(
    "Kevin"
    "Marquette"
)
'Hello, {0} {1}.' -f $values

Isso não é splatting porque estou passando toda a matriz, mas a ideia é semelhante.

Formatação avançada

Eu intencionalmente chamei isso como vindo do .NET porque há muitas opções de formatação já bem documentadas nele. Existem maneiras internas de formatar vários tipos de dados.

"{0:yyyyMMdd}" -f (Get-Date)
"Population {0:N0}" -f  8175133
20211110
Population 8,175,133

Eu não vou entrar neles, mas eu só queria que você saiba que este é um motor de formatação muito poderoso, se você precisar.

Juntando cadeias de caracteres

Às vezes, você realmente quer concatenar uma lista de valores juntos. Há um -join operador que pode fazer isso por você. Ele ainda permite que você especifique um caractere para unir entre as cadeias de caracteres.

$servers = @(
    'server1'
    'server2'
    'server3'
)

$servers  -join ','

Se você quiser -join algumas cadeias de caracteres sem um separador, você precisa especificar uma cadeia de caracteres ''vazia . Mas se isso é tudo o que você precisa, há uma opção mais rápida.

[string]::Concat('server1','server2','server3')
[string]::Concat($servers)

Também vale a pena ressaltar que você também -split pode fazer cordas.

Join-Path

Isso geralmente é negligenciado, mas é um ótimo cmdlet para criar um caminho de arquivo.

$folder = 'Temp'
Join-Path -Path 'c:\windows' -ChildPath $folder

O melhor de tudo isso é que ele funciona as barras invertidas corretamente quando junta os valores. Isso é especialmente importante se você estiver usando valores de usuários ou arquivos de configuração.

Isso também vai bem com Split-Path e Test-Path. Eu também abordo estes no meu post sobre como ler e salvar em arquivos.

Strings são matrizes

Eu preciso mencionar a adição de strings aqui antes de continuar. Lembre-se de que uma cadeia de caracteres é apenas uma matriz de caracteres. Quando você adiciona várias cadeias de caracteres juntas, uma nova matriz é criada a cada vez.

Veja este exemplo:

$message = "Numbers: "
foreach($number in 1..10000)
{
    $message += " $number"
}

Parece muito básico, mas o que você não vê é que cada vez que uma string é adicionada a $message isso, uma string totalmente nova é criada. A memória é alocada, os dados são copiados e o antigo é descartado. Não é grande coisa quando é feito apenas algumas vezes, mas um loop como este realmente exporia o problema.

Construtor de Strings

StringBuilder também é muito popular para construir cadeias de caracteres grandes a partir de muitas cadeias de caracteres menores. A razão é porque ele apenas coleta todas as cadeias de caracteres que você adiciona a ele e só concatena todas elas no final quando você recupera o valor.

$stringBuilder = New-Object -TypeName "System.Text.StringBuilder"

[void]$stringBuilder.Append("Numbers: ")
foreach($number in 1..10000)
{
    [void]$stringBuilder.Append(" $number")
}
$message = $stringBuilder.ToString()

Mais uma vez, isso é algo para o qual estou entrando em contato com o .NET. Eu não uso mais com frequência, mas é bom saber que está lá.

Delimitação com suportes

Isso é usado para concatenação de sufixos dentro da cadeia de caracteres. Às vezes, sua variável não tem um limite de palavras limpo.

$test = "Bet"
$tester = "Better"
Write-Host "$test $tester ${test}ter"

Obrigado /u/real_parbold por isso.

Aqui está uma alternativa a esta abordagem:

Write-Host "$test $tester $($test)ter"
Write-Host "{0} {1} {0}ter" -f $test, $tester

Eu pessoalmente uso string de formato para isso, mas isso é bom saber incase você vê-lo na natureza.

Localizar e substituir tokens

Embora a maioria desses recursos limite sua necessidade de rolar sua própria solução, há momentos em que você pode ter grandes arquivos de modelo onde deseja substituir cadeias de caracteres dentro.

Vamos supor que você tenha puxado um modelo de um arquivo que tem muito texto.

$letter = Get-Content -Path TemplateLetter.txt -RAW
$letter = $letter -replace '#FULL_NAME#', 'Kevin Marquette'

Você pode ter muitos tokens para substituir. O truque é usar um token muito distinto que seja fácil de encontrar e substituir. Eu tendo a usar um caractere especial em ambas as extremidades para ajudar a distingui-lo.

Recentemente, encontrei uma nova forma de abordar esta questão. Eu decidi deixar esta seção aqui porque este é um padrão que é comumente usado.

Substitua vários tokens

Quando tenho uma lista de tokens que preciso substituir, adoto uma abordagem mais genérica. Eu os colocaria em uma hashtable e iteraria sobre eles para fazer a substituição.

$tokenList = @{
    Full_Name = 'Kevin Marquette'
    Location = 'Orange County'
    State = 'CA'
}

$letter = Get-Content -Path TemplateLetter.txt -RAW
foreach( $token in $tokenList.GetEnumerator() )
{
    $pattern = '#{0}#' -f $token.key
    $letter = $letter -replace $pattern, $token.Value
}

Esses tokens podem ser carregados de JSON ou CSV, se necessário.

ExecutionContext ExpandString

Há uma maneira inteligente de definir uma cadeia de substituição com aspas simples e expandir as variáveis mais tarde. Veja este exemplo:

$message = 'Hello, $Name!'
$name = 'Kevin Marquette'
$string = $ExecutionContext.InvokeCommand.ExpandString($message)

A chamada para .InvokeCommand.ExpandString no contexto de execução atual usa as variáveis no escopo atual para substituição. O importante aqui é que o $message pode ser definido muito cedo antes mesmo que as variáveis existam.

Se expandirmos um pouco isso, podemos realizar essa substituição repetidamente com valores diferentes.

$message = 'Hello, $Name!'
$nameList = 'Mark Kraus','Kevin Marquette','Lee Dailey'
foreach($name in $nameList){
    $ExecutionContext.InvokeCommand.ExpandString($message)
}

Continuar com esta ideia; Você pode estar importando um modelo de e-mail grande de um arquivo de texto para fazer isso. Tenho de agradecer a Mark Kraus por esta sugestão.

O que funciona melhor para si

Eu sou um fã da abordagem de string de formato. Eu definitivamente faço isso com as cadeias de caracteres mais complicadas ou se houver várias variáveis. Em qualquer coisa que seja muito curta, posso usar qualquer uma delas.

Mais alguma coisa?

Eu cobri muito terreno neste. Minha esperança é que você saia aprendendo algo novo.

Se você quiser saber mais sobre os métodos e recursos que tornam a interpolação de cadeia de caracteres possível, consulte a lista a seguir para obter a documentação de referência.