Powershell在单个命令行上组合变量表达式

时间:2018-06-06 18:47:26

标签: powershell variables escaping interpolation

我试图理解Powershell如何在命令行上处理变量表达式(例如,作为cmdlet的参数)。我似乎无法准确理解它如何解析涉及多个变量(和/或变量属性)的表达式。以下是基于以下预定义变量的示例:

$a = 'abc'
$b = 'def'
$f = Get-ChildItem .\Test.txt   # assuming such a file exists in the current directory

示例1:

echo $a$b

输出:abcdef

示例2:

echo $a\$b

输出:abc\def

示例3:

echo $f.BaseName

输出:Test

示例4:

echo $a\$f.BaseName

输出:abc\C:\Test.txt.BaseName

基本上,我不明白为什么我可以组合两个变量(例1和2),我可以使用变量属性(例3),但我不能将变量与其他变量属性组合(例4)。我尝试了各种转义序列(使用反引号)无济于事。

我意识到我可以使用$()样式表达式完成此操作,例如:

echo $($a + '\' + $f.BaseName)

我只是不明白为什么另一种形式(例子4)无效 - 在我看来它更清晰。

2 个答案:

答案 0 :(得分:2)

$()()之间存在一些细微差别。我会说在你的例子中,在大多数情况下,你应该使用()

当您需要更复杂的内容或无法在$()中使用的表达时,可以使用

()。请注意,$()的输出基本上类似于输出管道,所以有些事情可能会发生。例如,看看这两个的输出:

(1..10 -as [string[]]).GetType()
$(1..10 -as [string[]]).GetType()

在第二种情况下,[string[]]数组已展开,然后重新分组为PowerShell的默认数组输出类型[object[]]

See this GitHub issue for more information about the vagaries of how arguments are treated and parsed when unquoted and ungrouped

答案 1 :(得分:2)

<强> TL; DR:

最安全的选项始终复合参数使用显式双引号,以便<强>通常string expansion (interpolation) rules申请。

应用于您的示例(我正在使用Write-Output,因为echo是PowerShell中的别名):

Write-Output "$a$b" # example 1
Write-Output "$a\$b" # example 2
Write-Output "$a\$($f.BaseName)" # example 4 - note the required $(...)

唯一的例外是示例3,因为您没有处理复合参数,而是单个表达式

Write-Output $f.BaseName # example 3: OK without quoting
Write-Output "$($f.BaseName)" # equivalent with double-quoting

PowerShell 主要是将复合参数视为双引号(即可扩展)字符串,但最终太多异常< / em>此行为有用

This GitHub issue总结了所有令人惊讶的行为。

至于您的具体问题

  

我无法将变量与其他变量属性组合在一起(例4)。

实际上,echo $a\$f.BaseName是一个复合令牌 被隐式处理的情况,好像它被包含在"..."中一样,正是因为你需要将$f.BaseName括在$(...)中,因为这是the string-expansion rules所需要的。

echo $a\$($f.BaseName)
  

我意识到我可以使用$()样式表达式完成此操作,例如:   echo $($a + '\' + $f.BaseName)

实际上,在这种情况下简单地使用(...)会更好,更有效,因为您要评估的是单个表达式

echo ($a + '\' + $f.BaseName)

briantist's helpful answer更多地关注(...)(仅限单一语句)和$(...)(使用管道逻辑的多个语句)之间的区别。