vaz*_*yte 4 powershell string-interpolation
我正在尝试编写一个函数,该函数将打印用户提供的问候语,该问候语发送给用户提供的名称.我想在这个代码块中使用扩展字符串:
$Name = "World"
$Greeting = "Hello, $Name!"
$Greeting
Run Code Online (Sandbox Code Playgroud)
哪个成功打印Hello, World!.但是,当我尝试将这些字符串作为参数传递给类似的函数时,
function HelloWorld
{
Param ($Greeting, $Name)
$Greeting
}
HelloWorld("Hello, $Name!", "World")
Run Code Online (Sandbox Code Playgroud)
我得到了输出
Hello, !
World
Run Code Online (Sandbox Code Playgroud)
经调查,PowerShell的似乎忽略了$Name在"Hello, $Name!"完全与运行
HelloWorld("Hello, !", "World")
Run Code Online (Sandbox Code Playgroud)
产生与上述相同的输出.此外,它似乎并不认为"World"是$Name运行以来 的价值
function HelloWorld
{
Param ($Greeting, $Name)
$Name
}
HelloWorld("Hello, $Name!", "World")
Run Code Online (Sandbox Code Playgroud)
不产生任何产出.
当作为函数参数传入时,有没有办法让扩展字符串工作?
为了延迟字符串插值并按需执行,使用当前值,您必须使用充当模板$ExecutionContext.InvokeCommand.ExpandString()的单引号字符串:
function HelloWorld
{
Param ($Greeting, $Name)
$ExecutionContext.InvokeCommand.ExpandString($Greeting)
}
HelloWorld 'Hello, $Name!' 'World' # -> 'Hello, World!'
Run Code Online (Sandbox Code Playgroud)
注意如何'Hello, $Name!'是单一 -quoted防止瞬间膨胀(插值).
还要注意如何HelloWorld调用它的参数用空格分隔,不用,和不用(...).
在PowerShell中,功能调用相似的命令行可执行文件 - foo arg1 arg2-不喜欢C#方法 - foo(arg1, arg2)-见Get-Help about_Parsing.
如果你不小心使用,分离你的论点,你将构建一个阵列,一个功能视为一个单一的参数.
为了帮助您避免意外使用方法语法,您可以使用Set-StrictMode -Version 2或更高,但请注意,这需要进行额外的严格性检查.
请注意,由于PowerShell函数默认情况下也会看到在父作用域(所有祖先作用域)中定义的变量,因此您可以简单地定义模板在调用作用域中引用的任何变量,而不是声明各个参数,例如$Name:
function HelloWorld
{
Param ($Greeting) # Pass the template only.
$ExecutionContext.InvokeCommand.ExpandString($Greeting)
}
$Name = 'World' # Define the variable(s) used in the template.
HelloWorld 'Hello, $Name!' # -> 'Hello, World!'
Run Code Online (Sandbox Code Playgroud)
警告:PowerShell字符串插值支持完整命令 - 例如,"Today is $(Get-Date)"- 因此,除非您完全控制或信任模板字符串,否则此技术可能存在安全风险.
安斯加尔Wiechers提出了一种安全的替代基于.NET字符串格式化通过PowerShell的-f操作和索引的占位符({0},{1},...):
请注意,您通常不再对参数应用转换作为模板字符串的一部分或嵌入命令.
function HelloWorld
{
Param ($Greeting, $Name)
$Greeting -f $Name
}
HelloWorld 'Hello, {0}!' 'World' # -> 'Hello, World!'
Run Code Online (Sandbox Code Playgroud)
陷阱:
PowerShell的字符串扩展使用不变文化,而-f运算符执行文化敏感格式(代码片段需要PSv3 +):
$prev = [cultureinfo]::CurrentCulture
# Temporarily switch to culture with "," as the decimal mark
[cultureinfo]::CurrentCulture = 'fr-FR'
# string expansion: culture-invariant: decimal mark is always "."
$v=1.2; "$v"; # -> '1.2'
# -f operator: culture-sensitive: decimal mark is now ","
'{0}' -f $v # -> '1,2'
[cultureinfo]::CurrentCulture = $prev
Run Code Online (Sandbox Code Playgroud)PowerShell的字符串扩展支持扩展集合(数组) - 它将它们扩展为以空格分隔的列表 - 而-f运算符仅支持标量(单个值):
$arr = 'one', 'two'
# string expansion: array is converted to space-separated list
"$var" # -> 'one two'
# -f operator: array elements are syntactically treated as separate values
# so only the *first* element replaces {0}
'{0}' -f $var # -> 'one'
# If you use a *nested* array to force treatment as a single array-argument,
# you get a meaningless representation (.ToString() called on the array)
'{0}' -f (, $var) # -> 'System.Object[]'
Run Code Online (Sandbox Code Playgroud)出现问题的原因是,在变量填充到函数$Name内部之前,字符串替换发生在函数外部。$Name
你可以这样做:
function HelloWorld
{
Param ($Greeting, $Name)
$Greeting -replace '\$Name',$Name
}
HelloWorld -Greeting 'Hello, $Name!' -Name 'World'
Run Code Online (Sandbox Code Playgroud)
通过使用单引号,我们发送 in 的字面问候语Hello, $Name,然后在函数内替换该字符串-Replace(我们必须在要替换的字符串\之前放置 a ,因为它是正则表达式特殊字符)。$$
| 归档时间: |
|
| 查看次数: |
391 次 |
| 最近记录: |