使用 ForEach-Object 而不是 foreach 时语法错误位置不精确

问题描述 投票:0回答:1

大多数时候,powershell 中的错误报告非常有用。我看到了错误,我看到了起源,但我注意到 ForEach-Object 管道中的任何错误都会丢失其起源行,并且错误堆栈只是指向带有

ForEach-Object
的代码行。

错误位置示例

Set-StrictMode -Version Latest
$ErrorActionPreference = "Stop"

[cultureinfo]::CurrentUICulture = 'en-US'

function Test-Something($val)
{
    # var is not defined here
    Write-Host($undefined_variable)
}

@("a","b") | ForEach-Object{
    $entry = $_

    Test-Something $entry
}

结果

ForEach-Object : The variable '$undefined_variable' cannot be retrieved because it has not been set.
In D:\dummy.ps1:12 Line:14
+ @("a","b") | ForEach-Object{
+              ~~~~~~~~~~~~~~~
    + CategoryInfo          : InvalidOperation: (undefined_variable:String) [ForEach-Object], RuntimeException
    + FullyQualifiedErrorId : VariableIsUndefined,Microsoft.PowerShell.Commands.ForEachObjectCommand

12
线指向
@("a","b") | ForEach-Object{
,这显然不是错误位置。

更有用的 foreach 示例

现在我使用的是

foreach
(只有最后4行代码发生了变化)

Set-StrictMode -Version Latest
$ErrorActionPreference = "Stop"

[cultureinfo]::CurrentUICulture = 'en-US'

function Test-Something($val)
{
    # var is not defined here
    Write-Host($undefined_variable)
}

$data = @("a","b")

foreach($entry in $data)
{
    Test-Something $entry
}

现在的错误更加有用,它实际上指向错误行

9
Write-Host($undefined_variable)

The variable '$undefined_variable' cannot be retrieved because it has not been set.
In D:\dummy.ps1:9 Line:16
+     Write-Host($undefined_variable)
+                ~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : InvalidOperation: (undefined_variable:String) [], ParentContainsErrorRecordException
    + FullyQualifiedErrorId : VariableIsUndefined

这是否与管道运营商的管道性质有关,或者我理解有误。当中间有更多函数时,第一种情况使得错误跟踪变得非常困难。在大多数情况下,我可以切换到

foreach
,但我很想了解实际发生的情况。

powershell error-handling
1个回答
0
投票

这可能过于简单化,具有更深入正式知识的人可能有更精确的技术答案,但值得注意的是

for
foreach
是“语言命令” - 即它们是PowerShell syntax
ForEach-Object
“只是”一个 cmdlet,例如
Invoke-Command
Get-ChldItem

因此,您的

foreach-object
示例相当于:

1 | $myScriptBlock = {
2 |     $entry = $_
3 | 
4 |     Test-Something $entry
5 | }
6 |
7 | @("a", "b") | foreach-object -process $myScriptBlock

PowerShell 的位置参数允许您使用与

foreach-object
类似的语法调用
for
,但底层机制不同,就 PowerShell 引擎而言,报告错误的代码行 top-level 是第 7 行,不是 4。

它不会追溯到定义脚本块的源代码行 - 在你的情况下它可能可以,但我猜在脚本块是从代码生成的更人为的情况下会很困难,例如

$myScriptBlock = [scriptblock]::Create(
    "`$entry = `$_" +
    "`r`n" +
    "Test-Something $entry"
)

@("a", "b") | foreach-object -process $myScriptBlock

什么情况下应该报哪个行号的错误?

© www.soinside.com 2019 - 2024. All rights reserved.