Compartilhar via


Tudo o que você queria saber sobre a substituição de variável em cadeias de caracteres

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

Observação

A versão original deste artigo foi publicada no blog escrito por @KevinMarquette. A equipe do PowerShell agradece kevin por compartilhar este conteúdo conosco. Confira o blog dele no PowerShellExplained.com.

Concatenação

A primeira classe de métodos pode ser conhecida como concatenação. É basicamente pegar várias cadeias de caracteres e juntá-las. Há um longo histórico de uso da concatenação para criar cadeias de caracteres formatadas.

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

A concatenação funciona bem quando há apenas alguns valores a serem adicionados. Mas isso pode ficar complicado rapidamente.

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

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

Substituição de variável

O PowerShell tem outra opção que é 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 cadeia de caracteres faz a diferença. Uma cadeia de caracteres entre aspas dupla permite a substituição, mas uma única cadeia de caracteres entre aspas não. Há ocasiões em que você deseja uma ou outra para que você tenha uma opção.

Substituição de comando

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

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

Você estaria esperando para obter o CreationTime off do $directory, mas em vez disso você obter isso Time: C:\windows.CreationTime como seu valor. O motivo é que esse tipo de substituição só vê a variável base. Ele considera o período como parte da cadeia de caracteres para que ele pare 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. Alguns objetos dão o nome do tipo, como System.Collections.Hashtable. Só algo para observar.

O PowerShell permite que você faça a execução de comando 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 bem para algumas situações, mas pode ficar tão louco quanto a concatenação se você tiver apenas algumas variáveis.

Execução de comando

Você pode executar comandos dentro de uma cadeia de caracteres. Mesmo que eu tenha essa opção, eu não gosto. Ele fica desordenado rapidamente e difícil de depurar. Executei o comando e salvei em uma variável ou uso uma cadeia de caracteres de formato.

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

Cadeia de formato

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 cadeia de caracteres é 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ê poderá colocar seus valores em uma matriz primeiro.

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

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

Formatação avançada

Eu os chamei intencionalmente como provenientes do .NET porque há muitas opções de formatação já bem documentadas nele. Há 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ê soubesse que este é um mecanismo de formatação muito poderoso se você precisar dele.

Junção de cadeias de caracteres

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

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

$servers  -join ','

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

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

Também vale a pena apontar que você também -split pode criar cadeias de caracteres.

Join-Path

Isso geralmente é ignorado, mas um grande cmdlet para a criação de um caminho de arquivo.

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

A grande coisa sobre isso é que ele trabalha as chicotadas corretamente quando coloca os valores juntos. Isso é especialmente importante se você estiver recebendo valores de usuários ou arquivos de configuração.

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

Cadeias de caracteres são matrizes

Preciso mencionar a adição de cadeias de caracteres 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 sempre que uma cadeia de caracteres é adicionada a $message essa nova cadeia de caracteres é 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.

StringBuilder

StringBuilder também é muito popular para criar cadeias de caracteres grandes de muitas cadeias de caracteres menores. O motivo é porque ele apenas coleta todas as cadeias de caracteres que você adiciona a ela 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()

Novamente, isso é algo para o qual estou entrando em contato com o .NET. Não uso mais, mas é bom saber que está lá.

Delineação com chaves

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

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

Obrigado Redditor 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 cadeia de caracteres de formato para isso, mas isso é bom saber no caso de você vê-lo na natureza.

Localizar e substituir tokens

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

Vamos supor que você puxou 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 é fácil de localizar e substituir. Eu costumo usar um caractere especial em ambas as extremidades para ajudar a distingui-lo.

Recentemente encontrei uma nova maneira de abordar isso. Decidi deixar esta seção aqui porque esse é um padrão que é comumente usado.

Substituir vários tokens

Quando tenho uma lista de tokens que preciso substituir, tomo uma abordagem mais genérica. Eu os colocaria em um 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 caracteres de substituição com aspas simples e expandir as variáveis posteriormente. Veja este exemplo:

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

A chamada para InvokeCommand.ExpandString o 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 das variáveis existirem.

Se expandirmos isso apenas um pouco, poderemos executar essa substituição várias e mais com valores diferentes.

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

Para continuar com essa ideia; você pode estar importando um modelo de email grande de um arquivo de texto para fazer isso. Tenho que agradecer a Mark Kraus por esta sugestão.

O que funcionar melhor para você

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

Mais alguma coisa?

Eu cobri muito chão sobre este. Espero que você vá embora aprendendo algo novo.

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