10

无论您想怎么称呼它,我都在尝试找出一种方法来获取现有字符串的内容并将它们评估为双引号字符串。例如,如果我创建以下字符串:

$string = 'The $animal says "meow"'
$animal = 'cat'

然后,Write-Host $string会产生The $animal says "meow". 如何重新评估 $string 以输出(或分配给新变量)The cat says "meow"


多么烦人……注释的限制使得包含反引号的代码变得非常困难(如果可能的话)。这是我在下面回复 zdan 时所做的最后两条评论的未修改版本:

----------

实际上,经过考虑,我意识到在The $animal says "meow"不转义双引号的情况下期望进行插值是不合理的,因为如果它是一个以双引号开头的字符串,那么如果不转义双引号,评估就会中断。所以我想答案是,这是一个两步过程:

$newstring = $string -replace '"', '`"'
iex "`"$string`""

给后人的最后一条评论:我尝试了将所有这些都放在一条线上的方法,几乎​​所有你认为可行的东西一旦你将它提供给 iex 就会中断,但这个可行:

iex ('"' + ($string -replace '"', '`"') + '"')
4

5 回答 5

9

可能最简单的方法是

$ExecutionContext.InvokeCommand.ExpandString($var)
于 2013-03-02T15:30:37.017 回答
8

您可以使用Invoke-Expression重新解析字符串 - 如下所示:

$string = 'The $animal says `"meow`"'
$animal = 'cat'
Invoke-Expression "Write-Host `"$string`""

请注意如何在字符串中转义双引号(使用反引号)以避免混淆解析器。这包括原始字符串中的任何双引号。

另请注意,第一个命令应该是一个命令,如果您需要使用生成的字符串,只需使用 write-output 管道输出并将其分配给您以后可以使用的变量:

$result = Invoke-Expression "write-output `"$string`""

如您的评论中所述,如果您无法修改字符串的创建以转义双引号,则必须自己执行此操作。您还可以将其包装在一个函数中以使其看起来更清晰:

function Invoke-String($str) { 
    $escapedString =  $str -replace '"', '`"'
    Invoke-Expression "Write-Output `"$escapedString`""
}

所以现在它看起来像这样:

# ~> $string = 'The $animal says "meow"'
# ~> $animal = 'cat'
# ~> Invoke-String $string
The cat says "meow"
于 2013-03-01T23:48:06.620 回答
4

您可以使用-f运算符。据我所知,这与调用相同[String]::Format

PS C:\> $string = 'The {0} says "meow"'
PS C:\> $animal = 'cat'
PS C:\> Write-Host ($string -f $animal)
The cat says "meow"

这避免了与引号剥离(由 ExpandStringand面临Invoke-Expression)和任意代码执行(由 面临Invoke-Expression)相关的陷阱。

我已经测试过它在版本 2 及更高版本中受支持;我不完全确定它是否存在于 PowerShell 1 中。

于 2016-03-09T00:15:00.070 回答
2

编辑:事实证明,字符串插值行为因 PowerShell 版本而异。我在 GitHub 上用单元测试编写了更好的xs( Expand-String) cmdlet 版本来处理这种行为。


这个解决方案的灵感来自这个关于在保留上下文的同时缩短对对象方法的调用的答案。您可以将以下函数放在某个实用程序模块中,当您从另一个模块调用它时它仍然有效:

function xs
{
    [CmdletBinding()]
    param
    (

        # The string containing variables that will be expanded.
        [parameter(ValueFromPipeline=$true,
                   Position=0,
                   Mandatory=$true)]
        [string]
        $String
    )
    process
    {
        $escapedString = $String -replace '"','`"'
        $code = "`$ExecutionContext.InvokeCommand.ExpandString(`"$escapedString`")"
        [scriptblock]::create($code)
    }
}

然后当你需要做延迟变量扩展时,你可以这样使用它:

$MyString = 'The $animal says $sound.'
...
$animal = 'fox'
...
$sound = 'simper'

&($MyString | xs)
&(xs $MyString)

PS> The fox says simper.
PS> The fox says simper.

$animal直到最后$sound两行才展开。这允许您设置一个$MyString预先和延迟扩展,直到变量具有您想要的值。

于 2015-02-20T22:25:39.900 回答
0
Invoke-Expression "`"$string`""
于 2017-04-06T11:56:48.350 回答