Comment concaténer des chaînes et des variables dans PowerShell?

611

Supposons que j'ai l'extrait de code suivant:

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

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

Je m'attends à ce que cet extrait montre:

42 - Slim Shady - Eminem

Mais à la place, cela montre:

42 + - + Slim Shady + - + Eminem

Ce qui me fait penser que l' +opérateur n'est pas approprié pour concaténer des chaînes et des variables.

Comment devez-vous aborder cela avec PowerShell?

Ninja Cowgirl
la source
28
Votre code fonctionne si tous les éléments sont des chaînes et vous mettez l'expression entre parenthèses: Write-host ($assoc.Id.ToString() + " - " + $assoc.Name + " - " + $assoc.Owner) ici $ assoc.Id est un Int32donc nous devons utiliser sa représentation sous forme de chaîne. Sinon, PS essaie d'effectuer une addition arithmétique au lieu d'une concaténation.
bouvierr
5
Étant donné le nombre de vues, j'ai pensé qu'il était approprié de réparer le texte de cette question, même si mes modifications ont quelque peu changé le contenu. J'ai essayé de garder intacte la terminologie / la formulation et l'esprit de la question, tout en l'améliorant suffisamment pour qu'elle puisse être rouverte.
Jeroen

Réponses:

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

Voir l' extension de sous-expressions Windows PowerShell Language Specification version 3.0 , p34.

David Brabant
la source
1
Cette technique fonctionne également avec Write-Output et al , c'est donc probablement la plus utile à avoir dans votre boîte à outils.
Fenton
4
Pourquoi le $ ($ name) vs juste $ name? Est-ce juste défensif de la même manière qu'en bash en utilisant $ {name}?
Danny Staple
73
Ce n'est pas techniquement une concaténation.
TravisEz13
8
@DannyStaple, la question a été tellement modifiée que la réponse n'a plus de sens. Dans l'exemple mince et louche, oui "... $name ..."fonctionnera tout de même, mais dans la question d'origine à laquelle cette réponse répond, la question est de savoir comment accéder aux propriétés des objets. donc si $name.id -eq 42alors "... $name.id ..."ne fonctionnerait pas comme vous le souhaitez, car il rendrait comme ... @{id=42}.id ...au lieu de la souhaitée ... 42 ...Pour cela, utilisez la méthode de la réponse "... $($name.id) ...". Je signets une question à modifier plus tard.
Jeff Puckett
3
Merci beaucoup de m'avoir indiqué la spécification du langage PowerShell. En tant que débutant, j'ai toujours été confus quant à la raison pour laquelle PowerShell ne vient pas avec un tutoriel officiel. Cette spécification de langue ressemble à ce que je recherche. Merci encore!
RayLuo
256

Personne ne semble avoir mentionné la différence entre les guillemets simples et doubles. (J'utilise PowerShell 4).

Vous pouvez le faire (comme l'a dit @Ben):

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

Ou vous pouvez le faire:

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

Les guillemets simples sont pour littéral, affichez la chaîne exactement comme ceci, s'il vous plaît. Les guillemets doubles sont pour quand vous voulez faire un prétraitement (comme les variables, les caractères spéciaux, etc.)

Donc:

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

Tandis que:

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

( http://ss64.com/ps/syntax-esc.html je trouve bon pour référence).

TinyRacoon
la source
1
Fonctionne également avec 1.0.
Smit Johnth
134

Une façon est:

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

Un autre est:

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

Ou juste (mais je n'aime pas ça;)):

Write-host $assoc.Id  "  -  "   $assoc.Name  "  -  "  $assoc.Owner
CB.
la source
7
Je ne pense pas que le dernier fonctionne exactement comme vous vous y attendez. Voir pastebin ici . Powershell ajoutera un espace (même si vous en avez deux ici) à la sortie pour l'espace blanc entre $assoc.Idet "(et al). Autrement dit, l'option 1 vous donne Id__-__Name__-__Owner(deux espaces de chaque côté de chacun -), mais l'option 3 donne Id___-___Name___-___Owner( trois espaces).
ruffin
4
Peut-être une boîte à pâte plus utile . $assoc.Id"###"$assoc.Name va ajouter des espaces de chaque côté de la ###, où "$($assoc.Id)###$($assoc.Name)" ne sera pas .
ruffin
1
le second m'a convaincu que powershell était ce dont j'avais besoin pour mes besoins - merci!
MaVCArt
123

Vous pouvez aussi utiliser -join

Par exemple

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

Attribuerait "John" à $ nom.

Donc, pour sortir, en une seule ligne:

Write-Host (-join("Jo", "h", "n"))
plusieurs façons
la source
au moins celui-ci pourrait être utilisé dans foreach
dEmigOd
68

Essayez d'envelopper tout ce que vous souhaitez imprimer entre parenthèses:

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

Votre code est interprété comme autant de paramètres transmis Write-Host. L'encapsuler entre parenthèses concatène les valeurs, puis transmet la valeur résultante en tant que paramètre unique.

goric
la source
3
+1, je préfère ce format lorsque j'utilise d'autres méthodes comme Write-Debugou Write-Verbosepour inclure des guillemets doubles et des valeurs variables, commeWrite-Debug ('Running "cmdlet" with parameter $MyVar = ' + $MyVar + " at time " + (Get-Date -DisplayHint Time))
IT Bear
Oui, c'est une concaténation de chaînes. Il n'ajoute pas de nouvelles lignes ni d'espaces supplémentaires. Il vous permet d'utiliser des chaînes entre guillemets simples ou doubles.
LexieHankins
Cette astuce est une véritable concaténation et vous permet de faire des chaînes multi-lignes, comme vous le feriez dans .net. Très bon pour faire des instructions SQL multilignes! Pourquoi PowerShell ne fait-il pas cela par défaut!?
Brain2000
Il y a plusieurs façons de procéder. Mais c'est la vraie réponse de la concaténation de chaînes.
chingNotCHing
32

Une autre option est:

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

La "meilleure" méthode est probablement celle suggérée par CB:

Write-host "$($assoc.Id)  -  $($assoc.Name)  -  $($assoc.Owner)"
Frode F.
la source
3
Vous devez ajouter l' StringBuilderoption si vous devenez fou. ; ^)
ruffin
2
il existe sûrement un moyen de canaliser les propriétés souhaitées dans un fichier externe, puis de les désérialiser en une chaîne de composants joints par des tirets (?)
Code Jockey
Il est difficile d'imaginer une approche pire que cela. Les chaînes étant immuables, chaque opération de concaténation produit en fait une nouvelle chaîne, copiant les caractères de l'original.
wombatonfire
22

Vous devez placer l'expression entre parenthèses pour éviter qu'elles ne soient traitées comme des paramètres différents de l'applet de commande:

Write-host ($assoc.Id + "  -  "  + $assoc.Name + "  -  " + $assoc.Owner)
Richard
la source
Ceci est obligatoire pour Write-Debug
Frank
19

Alors que l'expression:

"string1" + "string2" + "string3"

va concaténer les chaînes. Vous devez mettre un $ devant la parenthèse pour qu'elle soit évaluée comme un seul argument lorsqu'elle est passée à une commande powershell. Exemple:

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

En prime, si vous souhaitez qu'il s'étende sur plusieurs lignes, vous devez utiliser la syntaxe d'acquittement vers l'arrière à la fin de la ligne (sans espaces ni caractères à droite de l'arrière). Exemple:

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

(En fait, je pense que Powershell est actuellement implémenté un peu mal en nécessitant des retours en arrière inutiles entre parenthèses. Si Microsoft devait simplement suivre les règles de parenthèse "Python" ou "TCL" pour vous permettre de mettre autant de nouvelles lignes que vous le souhaitez entre le démarrage et la fin des parenthèses résoudrait alors la plupart des problèmes que les gens n'aiment pas à propos de la PowerShell liés à la continuation de ligne et à la concaténation des chaînes. J'ai trouvé que vous pouvez laisser les tiques en arrière parfois en ligne entre les parenthèses, mais sa vraiment floconneux et imprévisible si cela fonctionne .. il vaut mieux simplement ajouter les contre-coups.)

Bill Moore
la source
13

Voici une autre façon comme alternative:

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

Je veux juste apporter une autre façon de le faire en utilisant .NET String.Format :

$name = "Slim Shady"
Write-Host ([string]::Format("My name is {0}", $name))
Martin Brandl
la source
2
Y a-t-il un avantage à utiliser .NET String.Formatau lieu de l'ancienne plaine "{0}" -f $var? Je ne vois pas l'intérêt d'utiliser du code .NET où PowerShell ordinaire peut faire le travail ...
Dinei
4
@DineiRockenbach Probablement pas. Je voulais juste citer un autre exemple.
Martin Brandl
9

(Version PS actuelle 5.1.17134.407)

Tout est dit et fait maintenant, je suppose, mais cela fonctionne aussi à partir de maintenant:

$myVar = "Hello"

echo "${myVar} World"

Remarque: cela ne fonctionne qu'avec des guillemets doubles

Benjamin
la source
7

Ces réponses semblent toutes très compliquées. Si vous l'utilisez dans un script PowerShell, vous pouvez simplement le faire:

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

Il produira

Je m'appelle Slim Shady

Notez comment un espace est placé entre les mots pour vous

elev8ed
la source
6

Concaténer des chaînes comme au temps DOS. C'est un gros problème pour la journalisation, alors voilà:

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

Write-Output "$($strDate.Year)$($strDate.Month)$($strDate.Day)"
Write-Output $strday
Kelly Davis
la source
Pour les dates, je pense que l' toStringoption est plus simple:(Get-Date).toString('yyyyMMdd')
Tony il y a
6

Je semble avoir du mal avec cela (et bien d'autres choses non intuitives) chaque fois que j'utilise PowerShell après un temps loin de lui, alors j'opte maintenant pour:

[string]::Concat("There are ", $count, " items in the list")
Luke Puplett
la source
1
cela renvoie System.Object, fyi.
Barry
4

Write-Host peut également concaténer comme ceci:

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

C'est le moyen le plus simple, à mon humble avis.

Mordechai
la source
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
la source
2

Si vous concaténez des chaînes pour créer des chemins de fichier, utilisez la commande join-path:

join-path C:\temp "MyNewFolder"

Il ajoutera automatiquement les barres obliques de fin / de tête appropriées pour vous, ce qui rend les choses beaucoup plus faciles.

Je m'excuse si c'est trop hors sujet, mais j'ai pensé que cela pourrait aider certains.
Si je n'utilise pas PowerShell pendant un certain temps, parfois j'oublie qu'il existe et commence à rechercher les opérateurs de concaténation.

squicc
la source
0

Vous pouvez également accéder aux méthodes C # /. NET, et les éléments suivants fonctionnent également:

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

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

Output:

Slim Shady, The real slim shady
Ian Robertson
la source
-2

Juste pour le plaisir. Vous pouvez également accéder directement aux valeurs du PSObject comme ci-dessous:

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

Mais si vous ne spécifiez pas que l'objet doit être ordonné, Powershell affichera les valeurs dans un ordre aléatoire. Il faut donc ajouter le drapeau [commandé]

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