Wie verkette ich Zeichenfolgen und Variablen in PowerShell?

609

Angenommen, ich habe den folgenden Ausschnitt:

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

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

Ich würde erwarten, dass dieses Snippet Folgendes zeigt:

42 - Slim Shady - Eminem

Aber stattdessen zeigt es:

42 + - + Slim Shady + - + Eminem

Aus diesem Grund denke ich, dass der +Operator nicht zum Verketten von Zeichenfolgen und Variablen geeignet ist.

Wie sollten Sie dies mit PowerShell angehen?

Ninja Cowgirl
quelle
28
Ihr Code funktioniert, wenn alle Elemente Zeichenfolgen sind und Sie den Ausdruck in Klammern setzen: Write-host ($assoc.Id.ToString() + " - " + $assoc.Name + " - " + $assoc.Owner) hier $ assoc.Id ist eine, Int32daher müssen wir seine Zeichenfolgendarstellung verwenden. Andernfalls versucht PS, anstelle der Verkettung eine arithmetische Addition durchzuführen.
Bouvierr
5
Angesichts der Anzahl der Aufrufe hielt ich es für angebracht, den Text dieser Frage zu reparieren, obwohl meine Änderungen den Inhalt erheblich verändert haben. Ich habe versucht, die Terminologie / den Wortlaut und den Geist der Frage beizubehalten, während ich sie so weit verbessert habe, dass sie wieder geöffnet werden kann.
Jeroen

Antworten:

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

Weitere Informationen finden Sie in der Windows PowerShell-Sprachspezifikation Version 3.0 , S. 34, Erweiterung der Unterausdrücke.

David Brabant
quelle
1
Diese Technik funktioniert auch mit Write-Output et al. , Daher ist sie wahrscheinlich die nützlichste in Ihrer Toolbox.
Fenton
4
Warum das $ ($ name) gegen nur $ name? Ist dies nur defensiv wie bei Bash mit $ {name}?
Danny Staple
73
Dies ist technisch gesehen keine Verkettung.
TravisEz13
8
@DannyStaple Die Frage wurde so oft bearbeitet , dass die Antwort keinen Sinn mehr ergibt. Im schmalen, schattigen Beispiel "... $name ..."funktioniert yes trotzdem, aber in der ursprünglichen Frage, für die diese Antwort adressiert ist, lautet die Frage, wie auf Objekteigenschaften zugegriffen werden kann. Wenn dies $name.id -eq 42dann "... $name.id ..."nicht so funktioniert, wie Sie es möchten, weil es ... @{id=42}.id ...anstelle des gewünschten Renderings angezeigt wird ... 42 ..., verwenden Sie dazu die Methode der Antwort "... $($name.id) ...". Ich setze ein Lesezeichen für eine Frage, die später bearbeitet werden soll.
Jeff Puckett
3
Vielen Dank, dass Sie mich auf die PowerShell-Sprachspezifikation hingewiesen haben. Als Anfänger war ich immer verwirrt darüber, warum PowerShell kein offizielles Tutorial enthält. Diese Sprachspezifikation sieht aus wie das, wonach ich suche. Danke noch einmal!
RayLuo
256

Niemand scheint den Unterschied zwischen einfachen und doppelten Anführungszeichen erwähnt zu haben. (Ich verwende PowerShell 4).

Sie können dies tun (wie @Ben sagte):

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

Oder Sie können dies tun:

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

Die einfachen Anführungszeichen stehen für Literal. Geben Sie die Zeichenfolge bitte genau so aus. Die doppelten Anführungszeichen gelten für den Fall, dass eine Vorverarbeitung durchgeführt werden soll (z. B. Variablen, Sonderzeichen usw.).

Damit:

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

Wohingegen:

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

( http://ss64.com/ps/syntax-esc.html Ich finde gut als Referenz).

TinyRacoon
quelle
1
Funktioniert auch mit 1.0.
Smit Johnth
134

Ein Weg ist:

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

Ein anderer ist:

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

Oder einfach (aber ich mag es nicht;)):

Write-host $assoc.Id  "  -  "   $assoc.Name  "  -  "  $assoc.Owner
CB.
quelle
7
Ich glaube nicht, dass der letzte genau so funktioniert, wie Sie es erwarten würden. Siehe Pastebin hier . Powershell fügt der Ausgabe ein Leerzeichen (obwohl Sie hier zwei haben) für das Leerzeichen zwischen $assoc.Idund "(et al.) Hinzu . Das heißt, Option 1 gibt Ihnen Id__-__Name__-__Owner(zwei Leerzeichen auf jeder Seite von jedem -), aber Option 3 gibt Id___-___Name___-___Owner( drei Leerzeichen).
Ruffin
4
Vielleicht ein nützlicherer Pastebin . $assoc.Id"###"$assoc.Name werden Räume zu beiden Seiten des ### hinzufügen, wo "$($assoc.Id)###$($assoc.Name)" wird nicht .
Ruffin
1
Der zweite hat mich überzeugt, dass Powershell das ist, was ich für meine Zwecke brauchte - danke!
MaVCArt
123

Sie können auch verwenden -join

Z.B

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

Würde "John" $ name zuweisen.

Also in einer Zeile ausgeben:

Write-Host (-join("Jo", "h", "n"))
viele Möglichkeiten
quelle
Zumindest könnte dieser
dEmigOd verwendet werden
68

Versuchen Sie, alles, was Sie ausdrucken möchten, in Klammern zu setzen:

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

Ihr Code wird als viele Parameter interpretiert, an die übergeben wird Write-Host. Wenn Sie es in Klammern setzen, werden die Werte verkettet und der resultierende Wert als einzelner Parameter übergeben.

goric
quelle
3
+1, ich bevorzuge dieses Format, wenn ich andere Methoden wie Write-Debugoder Write-Verbosezum Einfügen von doppelten Anführungszeichen und variablen Werten verwende, wie z. B.Write-Debug ('Running "cmdlet" with parameter $MyVar = ' + $MyVar + " at time " + (Get-Date -DisplayHint Time))
IT Bear
Ja, dies ist eine Zeichenfolgenverkettung. Es werden keine Zeilenumbrüche oder zusätzlichen Leerzeichen hinzugefügt. Sie können entweder einfache oder doppelte Zeichenfolgen verwenden.
LexieHankins
Dieser Trick ist eine echte Verkettung und ermöglicht es Ihnen, mehrzeilige Zeichenfolgen wie in .net zu erstellen. Sehr gut für mehrzeilige SQL-Anweisungen! Warum macht Powershell dies nicht standardmäßig?
Brain2000
Es gibt viele Möglichkeiten. Dies ist jedoch die wahre Antwort auf die Verkettung von Zeichenfolgen.
chingNotCHing
32

Eine weitere Option ist:

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

Die "beste" Methode ist wahrscheinlich die von CB vorgeschlagene:

Write-host "$($assoc.Id)  -  $($assoc.Name)  -  $($assoc.Owner)"
Frode F.
quelle
3
Sie müssen die StringBuilderOption hinzufügen, wenn Sie verrückt werden. ; ^)
Ruffin
2
Sicherlich gibt es eine Möglichkeit, die gewünschten Eigenschaften in eine externe Datei zu leiten und sie dann in eine Reihe von Komponenten zu deserialisieren, die mit Bindestrichen (?) verbunden sind
Code Jockey
Ein schlimmerer Ansatz ist kaum vorstellbar. Zeichenfolgen sind unveränderlich, sodass bei jeder Verkettungsoperation tatsächlich eine neue Zeichenfolge erstellt wird, die die Zeichen der ursprünglichen Zeichenfolge kopiert.
Wombatonfire
22

Sie müssen den Ausdruck in Klammern setzen, um zu verhindern, dass sie als unterschiedliche Parameter für das Cmdlet behandelt werden:

Write-host ($assoc.Id + "  -  "  + $assoc.Name + "  -  " + $assoc.Owner)
Richard
quelle
Dies ist obligatorisch für Write-Debug
Frank
19

Während Ausdruck:

"string1" + "string2" + "string3"

verkettet die Zeichenfolgen. Sie müssen ein $ vor die Klammer setzen, damit es als einzelnes Argument ausgewertet wird, wenn es an einen Powershell-Befehl übergeben wird. Beispiel:

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

Wenn Sie möchten, dass es mehrere Zeilen umfasst, müssen Sie als Bonus die ackward-Backtick-Syntax am Ende der Zeile verwenden (ohne Leerzeichen oder Zeichen rechts vom Backtick). Beispiel:

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

(Eigentlich denke ich, dass Powershell derzeit ein wenig falsch implementiert ist, da unnötige Backticks zwischen Klammern erforderlich sind. Wenn Microsoft nur die Regeln für "Python" - oder "TCL" -Klammern befolgen würde, können Sie zwischen dem Starten und "so viele Zeilenumbrüche setzen, wie Sie möchten Wenn Sie die Klammern beenden, lösen sie die meisten Probleme, die die Leute an Powershell im Zusammenhang mit der Zeilenfortsetzung und der Verkettung von Zeichenfolgen nicht mögen. Ich habe festgestellt, dass Sie die Back-Ticks manchmal bei Zeilenfortsetzungen zwischen Klammern weglassen können, aber es ist wirklich flockig und unvorhersehbar, wenn es funktioniert .. es ist besser, nur die Backticks hinzuzufügen.)

Bill Moore
quelle
13

Hier ist ein anderer Weg als Alternative:

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

Ich möchte nur einen anderen Weg finden, um dies mit .NET String.Format zu tun :

$name = "Slim Shady"
Write-Host ([string]::Format("My name is {0}", $name))
Martin Brandl
quelle
2
Gibt es einen Vorteil der Verwendung von .NET String.Formatanstelle der alten Ebene "{0}" -f $var? Ich sehe keinen Sinn in der Verwendung von .NET-Code, wo einfache PowerShell die Arbeit erledigen kann ...
Dinei
4
@DineiRockenbach Wahrscheinlich nicht. Ich wollte nur ein anderes Beispiel nennen.
Martin Brandl
9

(Aktuelle PS-Version 5.1.17134.407)

Es ist alles gesagt und getan, aber das funktioniert ab sofort auch:

$myVar = "Hello"

echo "${myVar} World"

Hinweis: Dies funktioniert nur mit doppelten Anführungszeichen

Benjamin
quelle
7

Diese Antworten scheinen alle sehr kompliziert zu sein. Wenn Sie dies in einem PowerShell-Skript verwenden, können Sie dies einfach tun:

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

Es wird ausgegeben

Mein Name ist Slim Shady

Beachten Sie, wie für Sie ein Leerzeichen zwischen den Wörtern eingefügt wird

erhöht
quelle
6

Verketten Sie Zeichenfolgen wie in den DOS-Tagen. Dies ist eine große Sache für die Protokollierung.

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

Write-Output "$($strDate.Year)$($strDate.Month)$($strDate.Day)"
Write-Output $strday
Kelly Davis
quelle
Für Daten denke ich, dass die toStringOption einfacher ist:(Get-Date).toString('yyyyMMdd')
Tony vor
6

Ich habe jedes Mal Probleme damit (und mit vielen anderen unintuitiven Dingen), wenn ich PowerShell nach einiger Zeit benutze. Deshalb entscheide ich mich jetzt für:

[string]::Concat("There are ", $count, " items in the list")
Luke Puplett
quelle
1
Dies gibt System.Object zurück, fyi.
Barry
4

Write-Host kann auch so verketten:

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

Dies ist meiner Meinung nach der einfachste Weg.

Mordechai
quelle
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
quelle
2

Wenn Sie Zeichenfolgen zum Erstellen von Dateipfaden verketten, verwenden Sie den Befehl join-path:

join-path C:\temp "MyNewFolder"

Es werden automatisch die entsprechenden nachgestellten / führenden Schrägstriche für Sie hinzugefügt, was die Sache viel einfacher macht.

Ich entschuldige mich, wenn dies zu weit vom Thema entfernt ist, aber ich dachte, es könnte einigen helfen.
Wenn ich PowerShell eine Weile nicht benutze, vergesse ich manchmal, dass es existiert, und suche nach den Verkettungsoperatoren.

squicc
quelle
0

Sie können auch auf C # /. NET-Methoden zugreifen, und Folgendes funktioniert ebenfalls:

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

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

Output:

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

Nur zum Spaß. Sie können auch wie folgt direkt auf die Werte des PSObject zugreifen:

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

Wenn Sie jedoch nicht angeben, dass das Objekt sortiert werden soll, zeigt Powershell die Werte in zufälliger Reihenfolge an. Also sollte die Flagge hinzufügen [bestellt]

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