Jak łączyć ciągi i zmienne w PowerShell?

609

Załóżmy, że mam następujący fragment kodu:

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

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

Spodziewałbym się, że ten fragment pokaże:

42 - Slim Shady - Eminem

Zamiast tego pokazuje:

42 + - + Slim Shady + - + Eminem

Co sprawia, że ​​uważam, że +operator nie jest odpowiedni do łączenia łańcuchów i zmiennych.

Jak do tego podejść z PowerShell?

Cowgirl Ninja
źródło
28
Twój kod działa, jeśli wszystkie elementy są ciągami, a wyrażenie jest zawarte w nawiasach: Write-host ($assoc.Id.ToString() + " - " + $assoc.Name + " - " + $assoc.Owner) tutaj $ assoc.Id jest Int32więc musimy użyć jego reprezentacji ciągu. W przeciwnym razie PS próbuje wykonać dodawanie arytmetyczne zamiast konkatenacji.
bouvierr
5
Biorąc pod uwagę liczbę wyświetleń, uważałem za stosowne naprawić tekst tego pytania, mimo że moje zmiany całkiem zmieniły treść. Starałem się zachować nienaruszoną terminologię / sformułowania i ducha pytania, jednocześnie ulepszając je na tyle, aby można je było ponownie otworzyć.
Jeroen

Odpowiedzi:

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

Zobacz specyfikację języka Windows PowerShell wersja 3.0 , str. 34, rozszerzenie podwyrażeń.

David Brabant
źródło
1
Technika ta działa ze Write-Output wsp też, więc jest to prawdopodobnie najbardziej użyteczne jeden mieć w swojej skrzynce narzędziowej.
Fenton
4
Dlaczego $ ($ name) a po prostu $ name? Czy to jest po prostu defensywne w taki sam sposób, jak w bash przy użyciu $ {name}?
Danny Staple
73
To nie jest technicznie konkatenacja.
TravisEz13
8
@DannyStaple pytanie zostało zredagowane tak bardzo, że odpowiedź nie ma już sensu. W smukłym, zacienionym przykładzie tak "... $name ..."będzie działać tak samo, ale w pierwotnym pytaniu, na które ta odpowiedź odpowiada, pytanie brzmi: jak uzyskać dostęp do właściwości obiektu. więc jeśli $name.id -eq 42wtedy "... $name.id ..."nie będzie działać tak, jak chcesz, ponieważ byłoby to uczynić jak ... @{id=42}.id ...zamiast żądanego ... 42 ...W tym celu należy użyć metody odpowiedź brzmi "... $($name.id) ...". Zakładki do pytania do edycji później.
Jeff Puckett,
3
Dziękuję bardzo za wskazanie mi specyfikacji języka PowerShell. Jako początkujący zawsze byłem zdezorientowany, dlaczego PowerShell nie jest dostarczany z oficjalnym samouczkiem. Ta specyfikacja języka wygląda tak, jak szukam. Dzięki jeszcze raz!
RayLuo
256

Wydaje się, że nikt nie wspomniał o różnicy między pojedynczymi i podwójnymi cudzysłowami. (Używam PowerShell 4).

Możesz to zrobić (jak powiedział @Ben):

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

Lub możesz to zrobić:

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

Pojedyncze cudzysłowy są dosłowne, proszę podać ciąg dokładnie tak jak ten. Podwójne cudzysłowy mają zastosowanie, gdy chcesz wykonać wstępne przetwarzanie (takie jak zmienne, znaki specjalne itp.)

Więc:

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

Natomiast:

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

( http://ss64.com/ps/syntax-esc.html Uważam, że jest dobry w celach informacyjnych).

TinyRacoon
źródło
1
Działa również z wersją 1.0.
Smit Johnth,
134

Jednym ze sposobów jest:

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

Kolejny to:

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

Lub po prostu (ale mi się nie podoba;)):

Write-host $assoc.Id  "  -  "   $assoc.Name  "  -  "  $assoc.Owner
CB.
źródło
7
Nie sądzę, że ten ostatni działa dokładnie tak, jak można się spodziewać. Zobacz pastebin tutaj . Program PowerShell doda jedno (nawet jeśli masz tutaj dwa) spacje do danych wyjściowych dla spacji między $assoc.Idi "(i innymi). Oznacza to, że opcja 1 daje Id__-__Name__-__Owner(dwa spacje po każdej stronie każdej -), ale opcja 3 daje Id___-___Name___-___Owner( trzy spacje).
ruffin,
4
Być może bardziej przydatna pasta do pisania . $assoc.Id"###"$assoc.Name będzie dodać spacje po obu stronach ###, gdzie "$($assoc.Id)###$($assoc.Name)" nie będzie .
ruffin,
1
drugi przekonał mnie, że jest mi potrzebny do moich celów - dzięki!
MaVCArt
123

Możesz także użyć -join

Na przykład

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

Przypisałby „John” do $ name.

Aby wyprowadzić, w jednym wierszu:

Write-Host (-join("Jo", "h", "n"))
wiele sposobów
źródło
przynajmniej ten można by użyć w foreach
dEmigOd
68

Spróbuj owinąć wszystko, co chcesz wydrukować w nawiasie:

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

Twój kod jest interpretowany jako przekazywany do wielu parametrów Write-Host. Zawijanie go w nawiasie połączy wartości, a następnie przekaże wynikową wartość jako pojedynczy parametr.

goric
źródło
3
+1, wolę ten format, gdy używam innych metod, takich jak Write-Debuglub w Write-Verbosecelu uwzględnienia podwójnych cudzysłowów i wartości zmiennych, takich jakWrite-Debug ('Running "cmdlet" with parameter $MyVar = ' + $MyVar + " at time " + (Get-Date -DisplayHint Time))
IT Bear
Tak, to jest konkatenacja łańcuchowa. Nie dodaje nowych linii ani dodatkowych spacji. Pozwala na użycie ciągów pojedynczych lub podwójnych.
LexieHankins
Ta sztuczka jest prawdziwą konkatenacją i pozwala wykonywać wieloliniowe łańcuchy, tak jak w .net. Bardzo dobre do wykonywania wielowierszowych instrukcji SQL! Dlaczego PowerShell nie robi tego domyślnie !?
Brain2000
Jest wiele sposobów na zrobienie tego. Ale to jest prawdziwa odpowiedź na konkatenację łańcuchów.
chingNotCHing
32

Inną opcją jest:

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

„Najlepszą” metodą jest prawdopodobnie ta, którą sugeruje CB:

Write-host "$($assoc.Id)  -  $($assoc.Name)  -  $($assoc.Owner)"
Frode F.
źródło
3
Musisz dodać tę StringBuilderopcję, jeśli idziesz szalony. ; ^)
ruffin
2
z pewnością istnieje sposób na przeniesienie pożądanych właściwości do pliku zewnętrznego, a następnie deserializację ich na ciąg składników połączonych łącznikami (?)
Code Jockey
Trudno wyobrazić sobie podejście gorsze od tego. Ciągi są niezmienne, więc każda operacja konkatenacji w rzeczywistości tworzy nowy ciąg, kopiując znaki pierwotnego.
wombatonfire,
22

Musisz umieścić wyrażenie w nawiasach, aby nie były traktowane jako inne parametry niż polecenie cmdlet:

Write-host ($assoc.Id + "  -  "  + $assoc.Name + "  -  " + $assoc.Owner)
Richard
źródło
Jest to obowiązkowe w przypadku debugowania z zapisem
Frank
19

Podczas wyrażania:

"string1" + "string2" + "string3"

połączy łańcuchy. Musisz umieścić $ przed nawiasiem, aby był oceniany jako pojedynczy argument po przekazaniu do polecenia PowerShell. Przykład:

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

Jako bonus, jeśli chcesz, aby obejmował wiele linii, musisz użyć składni backtick ackward na końcu linii (bez spacji lub znaków po prawej stronie backtick). Przykład:

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

(Właściwie myślę, że Powershell jest obecnie nieco zaimplementowany, ponieważ wymaga niepotrzebnych tyknięć wstecz między nawiasami. Jeśli Microsoft po prostu zastosuje się do reguł nawiasów „Python” lub „TCL”, pozwalając na wstawianie dowolnej liczby nowych wierszy między początkiem a kończąc nawias, rozwiążą większość problemów, których ludzie nie lubią na temat PowerShell związanej z kontynuacją linii i konkatenacją ciągów. Odkryłem, że możesz pozostawić zaznaczenia wsteczne czasami w kontynuacjach linii między nawiasami, ale jest to naprawdę płatkowe i nieprzewidywalne, jeśli zadziała ... lepiej po prostu dodać backticks.)

Bill Moore
źródło
13

Oto inny sposób jako alternatywa:

Write-host (" {0}  -  {1}  -  {2}" -f $assoc.Id, $assoc.Name, $assoc.Owner)
Dave Sexton
źródło
9

Chcę tylko przynieść inny sposób, aby to zrobić za pomocą .NET String.Format :

$name = "Slim Shady"
Write-Host ([string]::Format("My name is {0}", $name))
Martin Brandl
źródło
2
Czy jest jakaś zaleta używania .NET String.Formatzamiast starej zwykłej "{0}" -f $var? Nie widzę sensu w używaniu kodu .NET, w którym zwykły PowerShell może wykonać zadanie ...
Dinei
4
@DineiRockenbach Prawdopodobnie nie. Chciałem tylko przywołać inny przykład.
Martin Brandl
9

(Aktualna wersja PS 5.1.17134.407)

Wydaje mi się, że wszystko zostało już powiedziane i zrobione, ale teraz działa to również:

$myVar = "Hello"

echo "${myVar} World"

Uwaga: działa to tylko z podwójnymi cudzysłowami

Benzoes
źródło
7

Wszystkie te odpowiedzi wydają się bardzo skomplikowane. Jeśli używasz tego w skrypcie PowerShell, możesz po prostu to zrobić:

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

Wyjdzie

Nazywam się Slim Shady

Zwróć uwagę, jak między słowami jest wstawiana spacja

podniesiony
źródło
6

Łączy ciągi, tak jak w czasach DOS. To wielka sprawa dla logowania, więc proszę:

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

Write-Output "$($strDate.Year)$($strDate.Month)$($strDate.Day)"
Write-Output $strday
Kelly Davis
źródło
6

Wydaje mi się, że mam trudności z tym (i wieloma innymi nieintuicyjnymi rzeczami) za każdym razem, gdy korzystam z programu PowerShell po pewnym czasie, więc teraz wybieram:

[string]::Concat("There are ", $count, " items in the list")
Luke Puplett
źródło
1
zwraca System.Object, fyi.
Barry
3

Write-Host może również łączyć w ten sposób:

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

To najprostszy sposób, IMHO.

Mordechaj
źródło
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
źródło
2

Jeśli łączysz łańcuchy w celu budowania ścieżek plików, użyj polecenia join-path:

join-path C:\temp "MyNewFolder"

Automatycznie doda odpowiednie końcowe / końcowe ukośniki, co znacznie ułatwia.

Przepraszam, jeśli jest to zbyt nie na temat, ale pomyślałem, że to może trochę pomóc.
Jeśli nie używam programu PowerShell przez jakiś czas, czasami zapomnę, że istnieje i zacznę szukać operatorów konkatenacji.

squicc
źródło
0

Możesz także uzyskać dostęp do metod C # / .NET i działa również:

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

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

Output:

Slim Shady, The real slim shady
Ian Robertson
źródło
-2

Tylko dla zabawy. Możesz również uzyskać dostęp do wartości PSObject bezpośrednio jak poniżej:

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

Ale jeśli nie określisz, że obiekt powinien być zamówiony, Powershell wyświetli wartości w losowej kolejności. Więc powinienem dodać flagę [zamówioną]

$assoc = [pscustomobject] [ordered] @{
    Id = 42
    Name = "Slim Shady"
    Owner = "Eminem"
}
R.Amersfoort
źródło