如何在 PowerShell 中连接字符串和变量?
Posted
技术标签:
【中文标题】如何在 PowerShell 中连接字符串和变量?【英文标题】:How do I concatenate strings and variables in PowerShell? 【发布时间】:2013-02-13 08:06:54 【问题描述】:假设我有以下sn-p:
$assoc = New-Object PSObject -Property @
Id = 42
Name = "Slim Shady"
Owner = "Eminem"
Write-Host $assoc.Id + " - " + $assoc.Name + " - " + $assoc.Owner
我希望这个 sn-p 会显示:
42 - Slim Shady - Eminem
但它却显示:
42 + - + Slim Shady + - + Eminem
这让我觉得+
运算符不适合连接字符串和变量。
您应该如何使用 PowerShell 来解决这个问题?
【问题讨论】:
您的代码有效 if 所有元素都是字符串,并且您将表达式括在括号中:Write-host ($assoc.Id.ToString() + " - " + $assoc.Name + " - " + $assoc.Owner)
这里 $assoc.Id 是 Int32
所以我们必须使用它字符串表示。否则 PS 会尝试执行算术加法而不是串联。
考虑到浏览量,我认为修复这个问题的文本是合适的,尽管我的编辑改变了很多内容。我试图保持问题的术语/措辞和精神完好无损,同时对其进行了足够的改进,以便可以重新打开它。
【参考方案1】:
Write-Host "$($assoc.Id) - $($assoc.Name) - $($assoc.Owner)"
参见Windows PowerShell Language Specification Version 3.0, p34, 子表达式扩展。
【讨论】:
为什么是 $($name) 而不是 $name?这与使用 $name 的 bash 中的防御方式相同吗? 这不是技术上的串联。 @DannyStaple 这个问题有很多been edited,以至于答案不再有意义。在苗条的阴暗示例中,是的"... $name ..."
将完全一样,但是在此答案所针对的原始问题中,问题是如何访问对象属性。所以如果$name.id -eq 42
那么"... $name.id ..."
不会像你想要的那样工作,因为它会像... @id=42.id ...
而不是所需的... 42 ...
那样呈现为此,请使用答案的方法"... $($name.id) ..."
。我正在为问题添加书签以便稍后编辑。
非常感谢您向我指出 PowerShell 语言规范。作为一个初学者,我一直对为什么 PowerShell 没有附带官方教程感到困惑。这个语言规范看起来像我正在寻找的。再次感谢!
这不适用于跨多行分布字符串。请改用( $string1, $string2, $string3 ) -join ""
或($string1 + $string2 + $string3)
。使用这些方法,您可以在字符串之间使用空格(空格、制表符和换行符),但请确保 (1) 每个字符串在同一行后面都有一个逗号/空格,(2) 使用反引号字符 ` 在您的代码之间的任何空行的末尾,以及 (3) 如果您使用 -join
,则结束括号和 -join
运算符必须在同一行【参考方案2】:
单引号和双引号是有区别的。 (我使用的是 PowerShell 4)。
你可以这样做(Benjamin said):
$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
(我觉得 How-to: Escape characters, Delimiters and Quotes 很有参考价值)。
【讨论】:
也适用于 1.0。 此引用规则和连接演示适用于 'nix shell 脚本(例如 Bash),除了 PowerShell。仅便携性因素就赢得了我的投票。 我很惭愧地说我的脚本是用 "" 调试的,但是用 '' 编写带有字符串和变量的命令,这是几个小时的工作,这个答案是为了找出我做错了什么。难以置信!powershell
很简洁,会在Write-Host 'My name is'$name
中的字符串和变量内容之间放置一个空格【参考方案3】:
你也可以使用-join
例如
$var = -join("Hello", " ", "world");
将“Hello world”分配给 $var。
所以要在一行中输出:
Write-Host (-join("Hello", " ", "world"))
【讨论】:
至少这个可以用在foreach中 请补充,如果您使用命令作为输入,请将命令包装在 $() 中.....例如... -join($(cmd1), ",", $(cmd2 )) ...我花了太长时间才弄清楚,因为我是 powershell 的新手 @S.Melted 为什么要包裹在$()
里面?
经过进一步审查,我的需要只需要()
。例如:-join("Timestamp: ", Get-Date)
给出错误,而-join("Timestamp: ", (Get-Date))
运行正常。但是,this 解释了何时需要$()
。
Write-Host -join("Hello", " ", "world")
不会加入,因为整个 join
参数需要括号,包括 arg = join 的名称。【参考方案4】:
一种方法是:
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
【讨论】:
我不认为最后一个完全符合您的预期。见pastebin here。 Powershell 将为$assoc.Id
和"
(等)之间的空白添加一个(即使您在这里有两个)空间。也就是说,选项 1 为您提供 Id__-__Name__-__Owner
(每个 -
的每侧两个空格),但选项 3 提供 Id___-___Name___-___Owner
(三个 个空格)。
Perhaps a more useful pastebin。 $assoc.Id"###"$assoc.Name
将在 ### 的任一侧添加空格,而 "$($assoc.Id)###$($assoc.Name)"
不会。【参考方案5】:
尝试将要打印的内容用括号括起来:
Write-Host ($assoc.Id + " - " + $assoc.Name + " - " + $assoc.Owner)
您的代码被解释为传递给Write-Host
的许多参数。将其包裹在括号内将连接这些值,然后将结果值作为单个参数传递。
【讨论】:
+1,当使用Write-Debug
或Write-Verbose
等其他方法来包含双引号和变量值时,我更喜欢这种格式,例如Write-Debug ('Running "cmdlet" with parameter $MyVar = ' + $MyVar + " at time " + (Get-Date -DisplayHint Time))
是的,这是字符串连接。它不会添加换行符或额外的空格。它允许您使用单引号或双引号字符串。
这个技巧是真正的连接,允许你做多行字符串,就像你在 .net 中一样。非常适合做多行 SQL 语句!为什么powershell默认不这样做!?
有很多方法可以做。但这是字符串连接的真正答案。
非常感谢!我很难为 Invoke-WebRequest 构建 URI 参数,而您的解决方案是唯一有效的解决方案:Invoke-WebRequest -uri ('http://mysvr/guestauth/app/rest/...'+$param1+'_'+$param2+'_something,count:10')
【参考方案6】:
另一种选择是:
$string = $assoc.ID
$string += " - "
$string += $assoc.Name
$string += " - "
$string += $assoc.Owner
Write-Host $string
“最佳”方法可能是 C.B. 建议的一种:
Write-Host "$($assoc.Id) - $($assoc.Name) - $($assoc.Owner)"
【讨论】:
如果你想继续疯狂,你需要添加StringBuilder
选项。 ;^)
肯定有一种方法可以将所需的属性通过管道传输到外部文件中,然后将它们反序列化为用连字符(?)连接的组件字符串
很难想象比这更糟糕的方法。字符串是不可变的,因此每个连接操作实际上都会产生一个新字符串,复制原始字符串的字符。
响应 Code Jockey 使用 += 可能每次都会产生一个新的字符串,但是对于一个相对较小的字符串添加额外的小字符串,谁在乎呢。清楚正在发生的事情是最重要的,而 PowerShell 让事情正常运行比其他任何事情都更重要。【参考方案7】:
while 表达式:
"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 的大多数与行继续和字符串连接相关的问题。
我发现你有时可以在括号之间的行继续上去掉反引号,但它是否会起作用真的很不稳定且不可预测......最好只添加反引号。)
【讨论】:
【参考方案8】:您需要将表达式放在括号中,以防止它们被视为 cmdlet 的不同参数:
Write-Host ($assoc.Id + " - " + $assoc.Name + " - " + $assoc.Owner)
【讨论】:
Write-Debug 是强制的【参考方案9】:这是另一种替代方法:
Write-Host (" 0 - 1 - 2" -f $assoc.Id, $assoc.Name, $assoc.Owner)
【讨论】:
【参考方案10】:(当前 PowerShell 版本 5.1.17134.407)
这也适用于现在:
$myVar = "Hello"
echo "$myVar World"
注意:这只适用于双引号
【讨论】:
【参考方案11】:我只是想用另一种方式来使用 .NET String.Format:
$name = "Slim Shady"
Write-Host ([string]::Format("My name is 0", $name))
【讨论】:
使用 .NETString.Format
代替旧的普通 "0" -f $var
有什么好处吗?我没有看到使用 .NET 代码的意义,而普通的 PowerShell 可以完成这项工作......
@DieiRockenbach 可能不会。只是想举一个例子。【参考方案12】:
每次使用 PowerShell 后,我似乎都在为这个(以及许多其他不直观的事情)而苦恼,所以我现在选择:
[string]::Concat("There are ", $count, " items in the list")
【讨论】:
这会返回 System.Object,仅供参考。【参考方案13】:这些答案看起来都很复杂。如果您在 PowerShell 脚本中使用它,您可以简单地执行以下操作:
$name = 'Slim Shady'
Write-Host 'My name is'$name
会输出
我的名字是斯利姆·谢迪
注意单词之间的空格是如何给你的
【讨论】:
【参考方案14】:来自What To Do / Not to Do in PowerShell: Part 1:
$id = $assoc.Id
$name = $assoc.Name
$owner = $assoc.owner
"$id - $name - $owner"
【讨论】:
【参考方案15】:就像在 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')
【参考方案16】:
Write-Host 也可以这样连接:
Write-Host $assoc.Id" - "$assoc.Name" - "$assoc.Owner
这是最简单的方法,恕我直言。
【讨论】:
【参考方案17】:如果您要连接字符串来构建文件路径,请使用Join-Path 命令:
Join-Path C:\temp "MyNewFolder"
它会自动为您添加适当的尾随/前导斜杠,这使事情变得容易得多。
【讨论】:
【参考方案18】:$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
【讨论】:
【参考方案19】:您还可以访问 C#/.NET 方法,以下方法也可以使用:
$string1 = "Slim Shady, "
$string2 = "The real slim shady"
$concatString = [System.String]::Concat($string1, $string2)
Output:
Slim Shady, The real slim shady
【讨论】:
【参考方案20】:只是为了好玩。您还可以直接访问 PSObject 的值,如下所示:
$assoc.psobject.Properties.value -join " - "
但是如果你没有指定对象应该是有序的,PowerShell 会以随机顺序显示这些值。所以你应该添加标志[ordered]
:
$assoc = [pscustomobject] [ordered] @
Id = 42
Name = "Slim Shady"
Owner = "Eminem"
【讨论】:
我看不出有人应该否决这个答案的任何理由。来自我的 +1。【参考方案21】:如其他地方所述,您可以使用 join。
如果您使用命令作为输入(就像我一样),请使用以下语法:
-join($(Command1), "," , $(Command2))
这将导致两个输出用逗号分隔。
相关评论见https://***.com/a/34720515/11012871
【讨论】:
【参考方案22】:我个人比较喜欢这种风格:
[string]::Join(' - ', 42, 'Slim Shady', 'Eminem')
或基于上述(无序)对象:
[string]::Join(' - ',$assoc.psObject.Properties.value)
【讨论】:
以上是关于如何在 PowerShell 中连接字符串和变量?的主要内容,如果未能解决你的问题,请参考以下文章
在 Powershell 中,如何通过提供名称作为 $var 来设置环境变量?