Как объединить строки и переменные в PowerShell?

611

Предположим, у меня есть следующий фрагмент:

$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
Учитывая количество просмотров, я счел целесообразным восстановить текст этого вопроса, хотя мои правки довольно сильно изменили содержание. Я пытался сохранить терминологию / формулировку и дух вопроса в неизменном виде, при этом улучшая его настолько, чтобы он мог быть вновь открыт.
Йерун

Ответы:

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

См. Спецификацию языка Windows PowerShell версии 3.0 , p34, расширение подвыражений.

Дэвид Брабант
источник
1
Этот метод работает и с Write-Output другими , поэтому, вероятно, он наиболее полезен в вашем наборе инструментов.
Фентон
4
Почему $ ($ name) против только $ name? Является ли это просто защитой так же, как в bash с использованием $ {name}?
Дэнни Стейпл
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 Я считаю хорошим для справки).

TinyRacoon
источник
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
CB.
источник
7
Я не думаю, что последний работает точно так, как вы ожидаете. Смотри pastebin здесь . Powershell добавит одно (хотя у вас их два) пространство к выводу для пробела между $assoc.Idи "(и др.). То есть вариант 1 дает вам Id__-__Name__-__Owner(два пробела с каждой стороны каждого -), но вариант 3 дает Id___-___Name___-___Owner( три пробела).
ruffin
4
Возможно, более полезный пастин . $assoc.Id"###"$assoc.Name будет добавлять пробела в обеих стороны от ###, где "$($assoc.Id)###$($assoc.Name)" не будет .
Ерш
1
второй убедил меня, что PowerShell - это то, что мне нужно для моих целей - спасибо!
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. Заключение его в круглые скобки объединит значения, а затем передаст полученное значение как один параметр.

goric
источник
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! Почему PowerShell не делает это по умолчанию !?
Brain2000
Есть много способов сделать. Но это верный ответ объединения строк.
chingNotCHing
32

Другой вариант:

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

«Лучшим» методом, вероятно, является тот, который предложил CB:

Write-host "$($assoc.Id)  -  $($assoc.Name)  -  $($assoc.Owner)"
Фроде Ф.
источник
3
Вам нужно добавить StringBuilderопцию, если вы сходите с ума. ; ^)
Ерш
2
несомненно, есть способ передать нужные свойства во внешний файл, а затем десериализовать их в строку компонентов, объединенных дефисами (?)
Code Jockey
Трудно представить себе худший подход. Строки являются неизменяемыми, поэтому каждая операция конкатенации фактически создает новую строку, копируя символы оригинальной.
wombatonfire
22

Вы должны поместить выражение в скобки, чтобы они не обрабатывались как командлет:

Write-host ($assoc.Id + "  -  "  + $assoc.Name + "  -  " + $assoc.Owner)
Ричард
источник
Это обязательно для записи-отладки
Фрэнк
19

Пока выражение:

"string1" + "string2" + "string3"

объединит строки. Вам нужно поставить $ перед скобками, чтобы он передавался как один аргумент при передаче в команду powershell. Пример:

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

В качестве бонуса, если вы хотите, чтобы он занимал несколько строк, вам нужно использовать синтаксис обратного обратного удара в конце строки (без пробелов или символов справа от обратного удара). Пример:

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

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

Билл Мур
источник
13

Вот другой способ в качестве альтернативы:

Write-host (" {0}  -  {1}  -  {2}" -f $assoc.Id, $assoc.Name, $assoc.Owner)
Дейв Секстон
источник
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 может выполнять эту работу ...
Диней
4
@DineiRockenbach Наверное, нет. Просто хотел привести еще один пример.
Мартин Брандл
9

(Текущая версия PS 5.1.17134.407)

Это все сказано и сделано к настоящему времени, я думаю, но это также работает на данный момент:

$myVar = "Hello"

echo "${myVar} World"

Примечание: это работает только с двойными кавычками

Вениамин
источник
7

Все эти ответы кажутся очень сложными. Если вы используете это в скрипте PowerShell, вы можете просто сделать это:

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

Будет выводить

Меня зовут Слим Шейди

Обратите внимание, как для вас ставится пробел между словами

elev8ed
источник
6

Конкатенация строк, как в дни DOS. Это большое дело для регистрации, так что здесь вы идете:

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

Write-Output "$($strDate.Year)$($strDate.Month)$($strDate.Day)"
Write-Output $strday
Келли Дэвис
источник
Что касается дат, я думаю, что toStringвариант проще:(Get-Date).toString('yyyyMMdd')
Тони
6

Я, кажется, борюсь с этим (и многими другими не интуитивными вещами) каждый раз, когда я использую PowerShell, после того как время отошло от него, поэтому теперь я выбираю:

[string]::Concat("There are ", $count, " items in the list")
Люк Пуплетт
источник
1
это возвращает System.Object, FYI.
Барри
4

Write-Host также может объединяться следующим образом:

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

Это самый простой способ, ИМХО.

Мордехай
источник
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
источник
2

Если вы объединяете строки для создания путей к файлам, используйте команду join-path:

join-path C:\temp "MyNewFolder"

Он автоматически добавит подходящие косые / ведущие слэши для вас, что намного упростит задачу.

Я извиняюсь, если это слишком не по теме, но я подумал, что это может помочь некоторым.
Если я некоторое время не использую PowerShell, иногда я забываю о его существовании и начинаю искать операторы конкатенации.

squicc
источник
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

Просто для удовольствия. Вы также можете получить доступ к значениям PSObject напрямую, как показано ниже:

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

Но если вы не укажете, что объект должен быть упорядочен, Powershell отобразит значения в случайном порядке. Поэтому следует добавить флаг [заказано]

$assoc = [pscustomobject] [ordered] @{
    Id = 42
    Name = "Slim Shady"
    Owner = "Eminem"
}
R.Amersfoort
источник