ChatGPT解决这个技术问题 Extra ChatGPT

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

假设我有以下片段:

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

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

我希望这个片段显示:

42 - Slim Shady - 阿姆

但相反,它显示:

42 + - + Slim Shady + - + 阿姆

这让我认为 + 运算符不适合连接字符串和变量。

你应该如何使用 PowerShell 来解决这个问题?

您的代码如果所有元素都是字符串并且您将表达式括在括号中:Write-host ($assoc.Id.ToString() + " - " + $assoc.Name + " - " + $assoc.Owner) 这里 $assoc.Id 是一个 Int32,所以我们必须使用它的字符串表示。否则 PS 会尝试执行算术加法而不是串联。
考虑到我认为修复这个问题的文本的观点数量是合适的,即使我的编辑改变了很多内容。我试图保持问题的术语/措辞和精神完整,同时对其进行足够的改进,以便可以重新打开它。

D
David Brabant
Write-Host "$($assoc.Id) - $($assoc.Name) - $($assoc.Owner)"

请参阅 Windows PowerShell Language Specification Version 3.0, p34, 子表达式扩展。


为什么 $($name) 与 $name 相比?这与使用 ${name} 的 bash 中的防御方式相同吗?
这在技术上不是串联。
@DannyStaple 这个问题有很多 been edited 以至于答案不再有意义。在苗条的阴暗示例中,yes "... $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 运算符必须在同一行
P
Peter Mortensen

单引号和双引号是有区别的。 (我使用的是 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。
除了 PowerShell 之外,此引用规则和连接演示还适用于 'nix shell 脚本(例如 Bash)。仅便携性因素就赢得了我的投票。
我很惭愧地说我的脚本是用 "" 调试的,但是用 '' 编写带有字符串和变量的命令,这是几个小时的工作,而这个答案是为了找出我做错了什么。难以置信的!
powershell 很简洁,会在字符串和 Write-Host 'My name is'$name 中的变量内容之间放置一个空格
n
ndemou

您也可以使用 -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 的名称。
P
Peter Mortensen

一种方法是:

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)" 不会
P
Peter Mortensen

尝试将要打印的任何内容包装在括号中:

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

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


+1,当使用 Write-DebugWrite-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')
P
Peter Mortensen

另一种选择是:

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

“最佳”方法可能是 CB 建议的一种:

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

如果您要 concat-crazy,则需要添加 StringBuilder 选项。 ;^)
肯定有一种方法可以将所需的属性通过管道传输到外部文件中,然后将它们反序列化为用连字符连接的一串组件(?)
很难想象还有比这更糟糕的方法。字符串是不可变的,因此每个连接操作实际上都会产生一个新字符串,复制原始字符串的字符。
为了响应 Code Jockey Using += 可能每次都会产生一个新的字符串,但是对于一个相对较小的字符串添加像这样的额外的小字符串,谁在乎。清楚正在发生的事情是最重要的,而 PowerShell 只是让事情正常工作比其他任何事情都更重要。
P
Peter Mortensen

虽然表达:

"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 问题。

我发现您有时可以在括号之间的行继续上保留反引号,但是如果它会起作用,它真的很不稳定且不可预测......最好只添加反引号。)


P
Peter Mortensen

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

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

这对于写调试是强制性的
P
Peter Mortensen

(当前 PowerShell 版本 5.1.17134.407)

这也适用于现在:

$myVar = "Hello"

echo "${myVar} World"

注意:这只适用于双引号


P
Peter Mortensen

这是另一种方法:

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

M
Martin Brandl

我只想使用 .NET String.Format 带来另一种方法:

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

使用 .NET String.Format 而不是旧的普通 "{0}" -f $var 有什么好处吗?我没有看到使用 .NET 代码的意义,而普通的 PowerShell 可以完成这项工作......
@DineiRockenbach 可能不会。只是想举另一个例子。
L
Luke Puplett

每次使用 PowerShell 后,我似乎都在为这个(以及许多其他不直观的事情)而苦苦挣扎,所以我现在选择:

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

这将返回 System.Object,仅供参考。
P
Peter Mortensen

这些答案似乎都很复杂。如果您在 PowerShell 脚本中使用它,您可以简单地执行以下操作:

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

它会输出

我的名字是苗条的阴影

请注意如何在您的单词之间放置空格


P
Peter Mortensen

就像在 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')
T
Trisped

来自 What To Do / Not to Do in PowerShell: Part 1

$id = $assoc.Id
$name = $assoc.Name
$owner = $assoc.owner
"$id - $name - $owner"

P
Peter Mortensen

Write-Host 也可以像这样连接:

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

这是最简单的方法,恕我直言。


P
Peter Mortensen

如果您要连接字符串以构建文件路径,请使用 Join-Path 命令:

Join-Path C:\temp "MyNewFolder"

它会自动为您添加适当的尾随/前导斜杠,这使事情变得容易得多。


P
Peter Mortensen
$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

C
Carsten

个人比较喜欢这种风格:

[string]::Join(' - ', 42, 'Slim Shady', 'Eminem')

或基于上述(无序)对象:

[string]::Join(' - ',$assoc.psObject.Properties.value)

I
Ian Robertson

您还可以访问 C#/.NET 方法,以下内容也可以使用:

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

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

Output:

Slim Shady, The real slim shady

P
Peter Mortensen

只是为了好玩。您还可以直接访问 PSObject 的值,如下所示:

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

但是,如果您没有指定对象应该是有序的,PowerShell 将以随机顺序显示这些值。所以你应该添加标志 [ordered]

$assoc = [pscustomobject] [ordered] @{
    Id = 42
    Name = "Slim Shady"
    Owner = "Eminem"
}

我看不出有人应该否决这个答案的任何理由。 +1 来自我。
S
S. Melted

如其他地方所述,您可以使用 join。

如果您使用命令作为输入(就像我一样),请使用以下语法:

-join($(Command1), "," , $(Command2))

这将导致两个输出用逗号分隔。

有关相关评论,请参见 https://stackoverflow.com/a/34720515/11012871