如何在PowerShell中连接字符串和变量?

932
假设我有以下片段:
$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 中,使用 + 运算符连接字符串和变量可能不太合适。你应该如何解决这个问题?

50
如果所有元素都是字符串,并且将表达式括在括号内,您的代码就可以正常工作:Write-host ($assoc.Id.ToString() + " - " + $assoc.Name + " - " + $assoc.Owner)这里$assoc.Id是一个Int32,所以我们必须使用它的字符串表示形式。否则 PowerShell 将尝试执行算术加法而不是连接操作。 - bouvierr
8
鉴于这个问题的浏览量,我认为修复这个问题的文本是合适的,尽管我的编辑改变了内容。在改善问题以便重新开放的同时,我试图保持术语/措辞和问题的精神不变。 - Jeroen
22个回答

993

14
为什么要用 $($name) 而不是 $name?这是否与在 bash 中使用 ${name} 一样具有防御性? - Danny Staple
131
这在技术上并不是串联。 - TravisEz13
15
@DannyStaple 这个问题已经被编辑了很多次,导致答案不再合理。在 Slim Shady 的例子中,是的 "... $name ..." 仍然可以正常工作,但在该答案所回答的原始问题中,问题是如何访问对象属性。因此,如果 $name.id -eq 42,那么 "... $name.id ..." 就不能按照你想要的方式工作,因为它会呈现为 ... @{id=42}.id ... 而不是期望的 ... 42 ...。为此,请使用答案中的方法 "... $($name.id) ..."。我会将这个问题加入我的书签以便以后编辑。 - Jeff Puckett
3
非常感谢您向我指出了PowerShell语言规范。作为初学者,我一直很困惑为什么PowerShell没有官方教程。这份语言规范看起来正是我需要的。再次感谢! - RayLuo
4
这种方法不适用于将字符串分布在多行的情况。相反,使用( $string1, $string2, $string3 ) -join ""($string1 + $string2 + $string3)。通过这些方法,您可以在字符串之间插入空格、制表符和换行符,但是请确保 (1) 每个字符串后面都有逗号/空格在同一行上,(2) 在代码之间的任何空行末尾使用反引号字符 ,以及 (3) 如果使用了 -join,则结束括号和 -join` 运算符必须在同一行上。 - Dave F
显示剩余2条评论

379

单引号和双引号之间有区别。(我正在使用 PowerShell 4)。

你可以像 Benjamin 所说的那样做:

$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

(我发现如何:转义字符、定界符和引号 是一个好的参考资料。)


3
也适用于1.0版本。 - Smit Johnth
这个关于连接的引用规则和演示适用于“nix shell脚本(例如Bash),除了PowerShell。仅凭可移植性因素就赢得了我的支持。 - BuvinJ
我很惭愧地说,我在调试脚本时使用了 "",但是在使用字符串和变量编写命令时却使用了 '',这让我花费了数小时的工作时间才找到我的错误。真是难以置信! - Kyle Burkett
1
powershell is neat and will put a space between the string and the content of the variable in Write-Host 'My name is'$name - Timo

270
你还可以使用-join
例如:
$var = -join("Hello", " ", "world");

将“Hello world”分配给$var。

因此,要在一行中输出:

Write-Host (-join("Hello", " ", "world"))

10
至少这个可以在 foreach 中使用。 - dEmigOd
4
请注意,如果您正在使用命令作为输入,请将命令放在$()中......例如......-join($(cmd1), ",", $(cmd2))......由于我是PowerShell的新手,所以花了太长时间才弄清楚。 - S. Melted
1
@S.Melted 为什么要用 $() 包裹起来? - AlbatrossCafe
Write-Host -join("Hello", " ", "world") 不会连接,因为整个 join 参数都需要括号,包括参数名称 = join。 - Timo
谢谢,这正是我需要的东西,比如 $name = -join("✅ ", $_.Substring(2)) - Michael Murphy
显示剩余2条评论

155

一种方法是:

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

10
我认为最后一个选项并不完全符合您的期望。请参见此处的pastebin。虽然您在代码中有两个空格,但是PowerShell会在$assoc.Id"之间的空格添加一个空格到输出结果中。也就是说,选项1会给出Id__-__Name__-__Owner(每个“ - ”两侧都有两个空格),但是选项3会给出Id___-___Name___-___Owner(每个“ - ”三个空格)。 - ruffin

98

尝试将想要打印输出的内容包裹在括号中:

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

您的代码被解释为将多个参数传递给Write-Host。将其放在括号中将连接这些值,然后将结果作为单个参数传递。


4
我喜欢使用这种格式来记录其他方法(如Write-DebugWrite-Verbose),以包含双引号和变量值,例如Write-Debug ('Running "cmdlet" with parameter $MyVar = ' + $MyVar + " at time " + (Get-Date -DisplayHint Time)) - IT Bear
2
是的,这是字符串连接。它不会添加换行符或额外的空格。它允许您使用单引号或双引号字符串。 - LexH
3
这个技巧是真正的串联,可以让你像在 .net 中一样使用多行字符串。非常适合编写多行 SQL 语句!为什么 PowerShell 不默认支持这个功能呢? - Brain2000
非常感谢您的帮助!我在构建Invoke-WebRequest的URI参数时遇到了困难,而您的解决方案是唯一有效的:Invoke-WebRequest -uri ('http://mysvr/guestauth/app/rest/...'+$param1+'_'+$param2+'_something,count:10') - Andreas
我有一个使用情况,其中我已经在双引号("")中,不能使用“接受”的答案,因为它会在命令链的上一级中破坏我的字符串。你的答案非常有帮助,解决了我的问题。谢谢! - ZaxLofful

43

当表达式为真时:

"string1" + "string2" + "string3"

会将字符串连接起来,需要在括号前面放置 $ 符号,以使其在传递给PowerShell命令时评估为单个参数。例如:

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

作为额外的奖励,如果你想让它跨越多行,那么你需要在行末使用笨拙的反引号语法(在反引号的右侧没有任何空格或字符)。

示例:

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

实际上,我认为 PowerShell 目前的实现方式有一点问题,因为它要求在括号之间添加不必要的反引号。如果微软只是遵循PythonTcl的括号规则,允许您在起始和结束括号之间输入任意数量的换行符,则可以解决大多数与 PowerShell 相关的行延续和字符串连接问题。

我发现有时可以在括号之间的行延续上省略反引号,但这种方法很不可靠,无法预测是否会奏效...最好还是加上反引号。


42
另一个选项是:
$string = $assoc.ID
$string += " - "
$string += $assoc.Name
$string += " - "
$string += $assoc.Owner
Write-Host $string

“最好”的方法可能是C.B.建议的方法:
Write-Host "$($assoc.Id)  -  $($assoc.Name)  -  $($assoc.Owner)"

3
如果你要频繁连接字符串,建议添加 StringBuilder 选项。 ;^) - ruffin
2
肯定有一种方法可以将所需的属性导入到外部文件中,然后将它们反序列化为一个由连字符连接的组件字符串。 - Code Jockey
很难想象比这更糟糕的方法了。字符串是不可变的,因此每个连接操作实际上都会产生一个新的字符串,复制原始字符串的字符。 - wombatonfire
1
响应Code Jockey的评论,使用+=可能会每次产生一个新字符串,但对于像这样添加额外小字符串的相对较小的字符串,谁在乎呢。最重要的是清晰地了解正在发生的事情,并且在PowerShell中,让事情正常运行比任何其他事情都更重要。 - Action Dan

37

您需要将表达式放在括号中,以防止它们被视为 cmdlet 的不同参数:

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

1
这是Write-Debug的必选项。 - Frank

18

(当前PowerShell版本为5.1.17134.407)

目前这也可以工作:

$myVar = "Hello"

echo "${myVar} World"

注意:此方法仅适用于双引号


14
这里有另一种替代方法:
Write-Host (" {0}  -  {1}  -  {2}" -f $assoc.Id, $assoc.Name, $assoc.Owner)

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接