Як з'єднати рядки та змінні в PowerShell?


609

Припустимо, у мене є такий фрагмент:

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

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

Я очікую, що цей фрагмент покаже:

42 - Slim Shady - Eminem

Але натомість це показує:

42 + - + Slim Shady + - + Eminem

Що змушує мене думати, що +оператор не підходить для об'єднання рядків і змінних.

Як слід підходити до цього за допомогою PowerShell?


28
Ваш код працює, якщо всі елементи є рядками, і ви Write-host ($assoc.Id.ToString() + " - " + $assoc.Name + " - " + $assoc.Owner) вкладаєте вираз у круглі дужки: тут $ assoc.Id - це Int32так, що ми повинні використовувати його рядкове подання. В іншому випадку PS намагається виконати арифметичне додавання замість конкатенації.
bouvierr

5
Зважаючи на кількість переглядів, я вважав за доцільне відремонтувати текст цього запитання, навіть якщо мої правки змінили вміст досить сильно. Я намагався зберегти термінологію / формулювання та дух питання недоторканим, одночасно вдосконалюючи його, щоб воно могло бути відновлене.
Jeroen

Відповіді:


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

Див. Розділ Розширення суб-виразів Windows PowerShell, версія 3.0 , p34.


1
Ця методика також працює з Write-Output співавторами , тож, мабуть, найкориснішою є її в панелі інструментів.
Фентон

4
Чому $ ($ name) проти просто $ name? Це просто захисна так само, як і в bash, використовуючи $ {name}?
Danny Staple

73
Це технічно не є об'єднанням.
TravisEz13

8
@DannyStaple запитання було відредаговано настільки, що відповідь більше не має сенсу. У тонкому тінистому прикладі так "... $name ..."буде працювати все одно, але в оригінальному запитанні, на яке ця відповідь адресовано, питання полягає у тому, як отримати доступ до властивостей об'єкта. тому, якщо $name.id -eq 42тоді "... $name.id ..."не буде працювати так, як ви хочете, тому що він буде робити як ... @{id=42}.id ...замість бажаного. ... 42 ...Для цього використовуйте метод відповіді "... $($name.id) ...". Я запитую закладки, щоб відредагувати пізніше.
Джефф Пукетт

3
Дуже дякую, що вказали мені на специфікацію мови PowerShell. Як початківець мене завжди бентежить питання, чому PowerShell не приходить з офіційним підручником. Ця мовна специфіка виглядає як те, що я шукаю. Знову дякую!
RayLuo

256

Здається, ніхто не згадав про різницю між одинарними та подвійними лапками. (Я використовую PowerShell 4).

Ви можете це зробити (як @Ben сказав):

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

Або ви можете це зробити:

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

Одиночні лапки призначені для буквального, виведіть рядок саме так, будь ласка. Подвійні лапки призначені для виконання попередньої обробки (наприклад, змінних, спеціальних символів тощо)

Тому:

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

При цьому:

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

( http://ss64.com/ps/syntax-esc.html Я вважаю корисним для ознайомлення).


1
Працює і з 1.0.
Сміт Джонс

134

Один із способів:

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

Ще один:

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

Або просто (але мені це не подобається;)):

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

7
Я не думаю, що останній працює так, як ви очікували. Дивіться пастебін тут . Powershell додасть один (навіть якщо у вас тут два) простір для виводу пробілу між $assoc.Idта "(et al). Тобто варіант 1 дає вам Id__-__Name__-__Owner(два пробіли на кожній стороні кожного -), а варіант 3 дає Id___-___Name___-___Owner( три пробіли).
ruffin

4
Можливо, більш корисний пастебін . $assoc.Id"###"$assoc.Name буде додавати пробілу в обох сторони від ###, де "$($assoc.Id)###$($assoc.Name)" НЕ буде .
ruffin

1
другий мене переконав, що повноваження - це те, що мені потрібно для моїх цілей - дякую!
MaVCArt

123

Ви також можете використовувати -join

Напр

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

Призначив би "Джон" до $ name.

Отже, для виведення в одному рядку:

Write-Host (-join("Jo", "h", "n"))

принаймні, це можна було б використовувати в foreach
dEmigOd

68

Спробуйте упакувати все, що ви хочете роздрукувати в дужках:

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

Ваш код інтерпретується як багато параметрів, які передаються Write-Host. Згортаючи його всередині дужок, об'єднуються значення та передають отримане значення як єдиний параметр.


3
+1, я віддаю перевагу цьому формату, коли використовую інші методи, такі як Write-Debugабо Write-Verboseдля включення подвійних лапок та змінних значень, таких якWrite-Debug ('Running "cmdlet" with parameter $MyVar = ' + $MyVar + " at time " + (Get-Date -DisplayHint Time))
IT Bear

Так, це рядкове з'єднання. Він не додає нових рядків або додаткових пробілів. Це дозволяє вам використовувати або окремі або двоцитувані рядки.
LexieHankins

Цей трюк є справжньою конкатенацією і дозволяє робити багаторядкові рядки, як і в .net. Дуже добре для створення багаторядкових операторів SQL! Чому не повноваження це роблять за замовчуванням !?
Brain2000

Є багато способів зробити. Але це справжня відповідь конкатенації рядків.
chingNotCHing

32

Ще один варіант:

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

"Найкращий" метод, мабуть, запропонований ЦБ:

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

3
Вам потрібно додати StringBuilderпараметр, якщо ви збираєтеся конкрет-божевільний. ; ^)
рюш

2
безумовно, є спосіб передати потрібні властивості у зовнішній файл, а потім десеріалізувати їх у рядок компонентів, з’єднаних дефісами (?)
Code Jockey

Важко уявити собі заступник гірший за цей. Рядки є незмінними, тому кожна операція конкатенації насправді створює новий рядок, копіюючи символи оригіналу.
вогняний вогонь

22

Вам потрібно розмістити вираз у дужках, щоб вони не трактувались як різні параметри командлету:

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

Це обов'язково для Write-Debug
Frank

19

Під час вираження:

"string1" + "string2" + "string3"

буде об'єднувати рядки. Потрібно поставити $ перед дужки, щоб він оцінив як єдиний аргумент при передачі команді powershell. Приклад:

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

Як бонус, якщо ви хочете, щоб він охоплював кілька рядків, тоді вам потрібно використовувати синтаксис ackward backtick в кінці рядка (без пробілів чи символів праворуч від вибору). Приклад:

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

(Насправді, я думаю, що в даний час Powershell реалізований трохи неправильно, вимагаючи непотрібних зворотних кліщів між дужками. Якщо Microsoft просто дотримуватиметься правил "Python" або "TCL" Parenthesis, що дозволяє вам розміщувати стільки нових рядків, скільки ви хочете, між початковим і початковим закінчуючи дужки, тоді вони вирішили б більшість проблем, які людям не подобаються у зв'язку із продовженням рядків та об'єднанням рядків. Я виявив, що ви можете іноді залишати зворотні відмітки на продовження рядків між дужками, але його насправді лускатий і непередбачуваний, якщо він буде працювати .. його краще просто додати підпори.)



9

Я просто хочу запропонувати інший спосіб зробити це за допомогою .NET String.Format :

$name = "Slim Shady"
Write-Host ([string]::Format("My name is {0}", $name))

2
Чи є якась перевага використання .NET String.Formatзамість старої простої "{0}" -f $var? Я не бачу сенсу в застосуванні .NET-коду, коли звичайний PowerShell може виконати цю роботу ...
Dinei

4
@DineiRockenbach Напевно, ні. Просто хотів підвести ще один приклад.
Мартін Брандл

9

(Поточна версія PS 5.1.17134.407)

Це все сказано і зроблено на даний момент, я думаю, але це також працює зараз

$myVar = "Hello"

echo "${myVar} World"

Примітка. Це працює лише з подвійними цитатами


7

Ці відповіді всі здаються дуже складними. Якщо ви використовуєте це в сценарії PowerShell, ви можете просто зробити це:

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

Це виведе

Мене звуть Slim Shady

Зверніть увагу, як проміжок між словами поставлено для вас



6

Об'єднайте рядки так само, як у дні DOS. Це велика справа для ведення лісозаготівлі, тож ось тут:

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

Write-Output "$($strDate.Year)$($strDate.Month)$($strDate.Day)"
Write-Output $strday

6

Мені здається, що я боюся з цим (та багатьма іншими неінтуїтивними речами) кожного разу, коли я використовую PowerShell через час від нього, тому я зараз вирішую:

[string]::Concat("There are ", $count, " items in the list")

1
це повертає System.Object, fyi.
Баррі


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

2

Якщо ви об'єднуєте рядки для створення шляхів до файлів, використовуйте команду join-path:

join-path C:\temp "MyNewFolder"

Це автоматично додасть відповідні кінці / провідні риски для вас, що полегшує роботу.

Прошу вибачення, якщо це занадто поза темою, але я подумав, що це може комусь допомогти.
Якщо я деякий час не використовую PowerShell, іноді забуду, що він існує, і почну шукати оператори з’єднання.


0

Ви також можете отримати доступ до методів C # /. NET, а також працює наступне:

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

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

Output:

Slim Shady, The real slim shady

-2

Просто для розваги. Ви також можете отримати доступ до значень об'єкта PSO безпосередньо як нижче:

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

Але якщо ви не вкажете, що об’єкт слід замовити, Powershell відобразить значення у випадковому порядку. Тому слід додати прапор [упорядковано]

$assoc = [pscustomobject] [ordered] @{
    Id = 42
    Name = "Slim Shady"
    Owner = "Eminem"
}
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.