Como concatenar seqüências de caracteres e variáveis ​​no PowerShell?

610

Suponha que eu tenha o seguinte snippet:

$assoc = New-Object psobject -Property @{
    Id = 42
    Name = "Slim Shady"
    Owner = "Eminem"
}

Write-host $assoc.Id + "  -  "  + $assoc.Name + "  -  " + $assoc.Owner

Eu esperava que esse trecho fosse exibido:

42 - Slim Shady - Eminem

Mas, em vez disso, mostra:

42 + - + Slim Shady + - + Eminem

O que me faz pensar que o +operador não é apropriado para concatenar seqüências de caracteres e variáveis.

Como você deve abordar isso com o PowerShell?

Ninja Cowgirl
fonte
28
Seu código funcionará se todos os elementos forem strings e você incluirá a expressão entre parênteses: Write-host ($assoc.Id.ToString() + " - " + $assoc.Name + " - " + $assoc.Owner) aqui $ assoc.Id é um, Int32então precisamos usar sua representação de strings. Caso contrário, o PS tenta executar uma adição aritmética em vez de concatenação.
bouvierr
5
Dado o número de visualizações, pensei que era apropriado reparar o texto desta pergunta, mesmo que minhas edições tenham mudado bastante o conteúdo. Tentei manter intacta a terminologia / redação e o espírito da pergunta, melhorando-a o suficiente para que possa ser reaberta.
Jeroen

Respostas:

667
Write-Host "$($assoc.Id) - $($assoc.Name) - $($assoc.Owner)"

Consulte o Windows PowerShell Language Specification versão 3.0 , p34, expansão de subexpressões.

David Brabant
fonte
1
Essa técnica também funciona com o Write-Output et al , portanto é provavelmente a mais útil na sua caixa de ferramentas.
Fenton
4
Por que $ ($ name) vs apenas $ name? Isso é apenas defensivo da mesma maneira que no bash usando $ {name}?
Danny Staple
73
Isso não é tecnicamente concatenação.
TravisEz13
8
@DannyStaple a pergunta foi editada tanto que a resposta não faz mais sentido. No exemplo slim shady, yes "... $name ..."funcionará da mesma forma, mas na pergunta original para a qual essa resposta é direcionada, a questão é como acessar as propriedades do objeto. por isso, se $name.id -eq 42depois "... $name.id ..."não iria funcionar como você quer porque tornaria como ... @{id=42}.id ...em vez do desejado ... 42 ...Para isso, use o método de resposta "... $($name.id) ...". Estou marcando uma pergunta para editar mais tarde.
perfil completo de Jeff Puckett
3
Muito obrigado por me indicar a Especificação de idioma do PowerShell. Como iniciante, sempre fiquei confuso sobre o motivo pelo qual o PowerShell não vem com um tutorial oficial. Essa especificação de idioma se parece com o que estou procurando. Obrigado novamente!
RayLuo
256

Parece que ninguém mencionou a diferença entre aspas simples e duplas. (Estou usando o PowerShell 4).

Você pode fazer isso (como @Ben disse):

$name = 'Slim Shady'
Write-Host 'My name is'$name
-> My name is Slim Shady

Ou você pode fazer isso:

$name = 'Slim Shady'
Write-Host "My name is $name"
-> My name is Slim Shady

As aspas simples são literais, produzem a string exatamente assim, por favor. As aspas duplas são para quando você deseja realizar um pré-processamento (como variáveis, caracteres especiais etc.)

Assim:

$name = "Marshall Bruce Mathers III"
Write-Host "$name"
-> Marshall Bruce Mathers III

Enquanto que:

$name = "Marshall Bruce Mathers III"
Write-Host '$name'
-> $name

( http://ss64.com/ps/syntax-esc.html acho bom para referência).

TinyRacoon
fonte
1
Também funciona com 1.0.
Smit Johnth
134

Uma maneira é:

Write-host "$($assoc.Id)  -  $($assoc.Name)  -  $($assoc.Owner)"

Outro é:

Write-host  ("{0}  -  {1}  -  {2}" -f $assoc.Id,$assoc.Name,$assoc.Owner )

Ou apenas (mas eu não gosto;)):

Write-host $assoc.Id  "  -  "   $assoc.Name  "  -  "  $assoc.Owner
CB.
fonte
7
Eu não acho que o último funcione exatamente como você esperaria. Veja pastebin aqui . O Powershell adicionará um (mesmo que você tenha dois aqui) à saída do espaço em branco entre $assoc.Ide "(et al). Ou seja, a opção 1 fornece Id__-__Name__-__Owner(dois espaços em cada lado de cada um -), mas a opção 3 fornece Id___-___Name___-___Owner( três espaços).
Ruffin
4
Talvez uma pasta mais útil . $assoc.Id"###"$assoc.Name irá adicionar espaços para cada lado do ###, onde "$($assoc.Id)###$($assoc.Name)" não vai .
Ruffin
1
o segundo me convenceu que PowerShell é o que eu precisava para meus propósitos - obrigado!
MaVCArt
123

Você também pode usar -join

Por exemplo

$name = -join("Jo", "h", "n");

Atribuiria "John" a $ name.

Então, para saída, em uma linha:

Write-Host (-join("Jo", "h", "n"))
várias maneiras
fonte
pelo menos este poderia ser usado em foreach
dEmigOd
68

Tente colocar o que você deseja imprimir entre parênteses:

Write-host ($assoc.Id + "  -  "  + $assoc.Name + "  -  " + $assoc.Owner)

Seu código está sendo interpretado como muitos parâmetros sendo passados ​​para Write-Host. Envolvê-lo entre parênteses concatenará os valores e passará o valor resultante como um único parâmetro.

goric
fonte
3
+1, eu prefiro esse formato ao usar outros métodos como Write-Debugou Write-Verbosepara incluir aspas duplas e valores variáveis, comoWrite-Debug ('Running "cmdlet" with parameter $MyVar = ' + $MyVar + " at time " + (Get-Date -DisplayHint Time))
IT Bear
Sim, isso é concatenação de string. Não adiciona novas linhas ou espaços extras. Permite usar seqüências de caracteres simples ou duplas.
LexieHankins
Esse truque é uma verdadeira concatenação e permite que você crie seqüências de várias linhas, como faria em .net. Muito bom para fazer instruções SQL de várias linhas! Por que o PowerShell não faz isso por padrão !?
Brain2000
Existem muitas maneiras de fazer. Mas esta é a verdadeira resposta da concatenação de strings.
chingNotCHing 16/01
32

Outra opção é:

$string = $assoc.ID
$string += " - "
$string += $assoc.Name
$string += " - "
$string += $assoc.Owner
Write-Host $string

O "melhor" método é provavelmente o que o CB sugeriu:

Write-host "$($assoc.Id)  -  $($assoc.Name)  -  $($assoc.Owner)"
Frode F.
fonte
3
Você precisa adicionar a StringBuilderopção se estiver louco por concat. ; ^)
ruffin
2
certamente há uma maneira de tubo as propriedades desejadas em um arquivo externo, em seguida, desserializar-los em uma série de componentes unidos com hífens (?)
Código Jockey
É difícil imaginar uma abordagem pior do que isso. As strings são imutáveis; portanto, cada operação de concatenação produz uma nova string, copiando caracteres da original.
wombatonfire
22

Você precisa colocar a expressão entre parênteses para impedir que sejam tratadas como parâmetros diferentes para o cmdlet:

Write-host ($assoc.Id + "  -  "  + $assoc.Name + "  -  " + $assoc.Owner)
Richard
fonte
Isso é obrigatório para Write-Debug
Frank
19

Enquanto expressão:

"string1" + "string2" + "string3"

concatenará as cordas. Você precisa colocar um $ na frente dos parênteses para fazê-lo avaliar como um único argumento quando passado para um comando do PowerShell. Exemplo:

Write-Host $( "string1" + "string2" + "string3" ) 

Como bônus, se você deseja que ele abranja várias linhas, use a sintaxe do backtick desagradável no final da linha (sem espaços ou caracteres à direita do backtick). Exemplo:

Write-Host $(`
    "The rain in "        +`
    "Spain falls mainly " +`
    "in the plains"       )`
    -ForegroundColor Yellow

(Na verdade, acho que o Powershell está atualmente implementado um pouco errado, pois exige back-ticks desnecessários entre parênteses. Se a Microsoft seguir apenas as regras de parênteses "Python" ou "TCL", permitirá que você coloque quantas linhas novas desejar entre iniciar e terminando entre parênteses, eles resolveriam a maioria dos problemas que as pessoas não gostam sobre o PowerShell relacionados à continuação de linhas e concatenação de strings.Eu descobri que você pode deixar os back-ticks algumas vezes nas continuações de linha entre parênteses, mas é realmente flakey e imprevisível se funcionar. é melhor adicionar apenas os backticks.)

Bill Moore
fonte
13

Aqui está outra maneira como alternativa:

Write-host (" {0}  -  {1}  -  {2}" -f $assoc.Id, $assoc.Name, $assoc.Owner)
Dave Sexton
fonte
9

Eu só quero trazer outra maneira de fazer isso usando o .NET String.Format :

$name = "Slim Shady"
Write-Host ([string]::Format("My name is {0}", $name))
Martin Brandl
fonte
2
Existe alguma vantagem em usar o .NET em String.Formatvez da planície antiga "{0}" -f $var? Eu não vejo o ponto em usar código .NET onde o PowerShell simples pode fazer o trabalho ...
Dinei
4
@DineiRockenbach Provavelmente não. Só queria trazer outro exemplo.
Martin Brandl
9

(Versão atual do PS 5.1.17134.407)

Já está tudo dito e feito até agora, mas isso também funciona a partir de agora:

$myVar = "Hello"

echo "${myVar} World"

Nota: isso funciona apenas com aspas duplas

Benjamin
fonte
7

Todas essas respostas parecem muito complicadas. Se você estiver usando isso em um script do PowerShell, basta fazer o seguinte:

$name = 'Slim Shady'
Write-Host 'My name is'$name

Vai sair

Meu nome é Slim Shady

Observe como um espaço é colocado entre as palavras para você

elev8ed
fonte
6

Concatene seqüências de caracteres como nos dias do DOS. Este é um grande problema para o registro, então aqui está:

$strDate = Get-Date
$strday = "$($strDate.Year)$($strDate.Month)$($strDate.Day)"

Write-Output "$($strDate.Year)$($strDate.Month)$($strDate.Day)"
Write-Output $strday
Kelly Davis
fonte
Para datas, acho que a toStringopção é mais fácil:(Get-Date).toString('yyyyMMdd')
Tony
6

Eu pareço lutar com isso (e muitas outras coisas não intuitivas) toda vez que uso o PowerShell após um tempo fora dele, então agora opto por:

[string]::Concat("There are ", $count, " items in the list")
Luke Puplett
fonte
1
isso retorna System.Object, fyi.
Barry
4

O Write-Host também pode concatenar assim:

Write-Host $assoc.Id" - "$assoc.Name" - "$assoc.Owner

Esta é a maneira mais simples, IMHO.

Mordechai
fonte
2
$assoc = @{
    Id = 34
    FirstName = "John"
    LastName = "Doe"
    Owner = "Wife"
}

$assocId = $assoc.Id
$assocFN = $assoc.FirstName
$assocLN = $assoc.LastName
$assocName = $assocFN, $assocLN -Join " "
$assocOwner = $assoc.Owner

$assocJoin = $assocId, $assocName, $assocOwner -join " - "
$assocJoin
#Output = 34 - John Doe - Wife
blayderunner123
fonte
2

Se você estiver concatenando cadeias para criar caminhos de arquivos, use o comando join-path:

join-path C:\temp "MyNewFolder"

Ele adiciona automaticamente as barras à direita / à direita, o que facilita muito as coisas.

Peço desculpas se este tópico não for muito relevante, mas achei que poderia ajudar alguns.
Se eu não usar o PowerShell por um tempo, às vezes vou esquecer que ele existe e começar a procurar os operadores de concatenação.

squicc
fonte
0

Você também pode obter acesso aos métodos C # / .NET e o seguinte também funciona:

$string1 = "Slim Shady, "
$string2 = "The real slim shady"

$concatString = [System.String]::Concat($string1, $string2)

Output:

Slim Shady, The real slim shady
Ian Robertson
fonte
-2

Apenas pela diversão. Você também pode acessar os valores do PSObject diretamente como abaixo:

$assoc.psobject.Properties.value -join " - "

Mas se você não especificar que o objeto deve ser pedido, o Powershell exibirá os valores em uma ordem aleatória. Então deve adicionar a bandeira [ordenada]

$assoc = [pscustomobject] [ordered] @{
    Id = 42
    Name = "Slim Shady"
    Owner = "Eminem"
}
R.Amersfoort
fonte