Powershell最后使用Ctrl-C跳过块

时间:2017-07-14 13:41:14

标签: powershell powershell-v3.0 try-finally

我正在使用Try / Finally在Powershell中编写一个监视脚本,以便在脚本结束时记录消息。该脚本旨在无限期运行,因此我想要一种跟踪意外退出的方法。

其他所有StackOverflow帖子和Help page我都检查了状态:

  

即使您使用CTRL + C来停止脚本,也会运行Finally块。如果Exit关键字在Catch块中停止脚本,则也会运行Finally块。

在实践中,我没有发现这是真的。我正在使用以下设计的例子来测试它:

Try {
    While($True) {
        echo "looping"
        Start-Sleep 3
    }
} Finally {
    echo "goodbye!"
    pause
}

Ctrl + C (无回声,无暂停)后,每次跳过Finally块,无论是作为保存的脚本运行还是通过内置的Powershell ISE执行时。我得到的唯一输出是:

looping
looping
...(repeat until Ctrl-C)

我显然错过了一些东西,但我不知道它是什么,特别是在这么小的代码片段中。

2 个答案:

答案 0 :(得分:4)

正确的答案是 Ctrl + C 打破了管道,正如该链接中所述,echo使用管道来处理其输出。因此,一旦 Ctrl + C ,写入管道会导致脚本块出错,并且不会处理任何其他命令。因此,不要使用直接向stdout发送输出的命令,并且有很多间接使用管道的命令。另一方面,Write-Host不使用管道,因此不会抛出错误。

答案 1 :(得分:1)

功能代码

这将为您提供我相信您之后的行为:

Try {
    While($True) {
        echo "looping"
        Start-Sleep 3
    }
} Finally {
    Write-Host "goodbye!"
    pause
}

<强>参考

Write-Output/echo - Synopsis

  

将指定的对象发送到管道中的下一个命令。 如果该命令是管道中的最后一个命令,则对象将显示在控制台中。

Write-Host - Synopsis

  

将自定义输出写入主机。

Try-Catch-Finally - Syntax note

  

请注意,按CTRL + C会停止管道。 发送到管道的对象不会显示为输出。 因此,如果包含要显示的语句,例如&#34;最后块已运行&# 34;,即使最后一个块运行,也不会在按CTRL + C后显示。

<强>解释

根据TheIncorrigible1的评论和Vesper的回答,关键是 管道已停止 。但这不是因为Write-Output中的错误。而且我发现它本身并不令人满意。

  • &#34;如果命令是管道中的最后一个命令,则对象将显示在控制台中。&#34; - 在finally块中出现此语句为false。但是,明确传递给Out-Host将产生所需的输出。
  • On Try-Catch-Finally note
    • 引用的部分令人困惑,因为它适用于发送到管道的 未处理的对象
    • 发送到管道并在Finally块内处理的对象都可以。
    • 它讨论&#34;即使最后一个块已经运行&#34; pause如果前面有Write-Output则不会运行。

更多代码

Finally区块中运行了一些事情来调查行为,并对发生的事情发表评论。

} Finally {
    Write-Output "goodbye!" | Out-Default # works fine
    pause
}
} Finally {
    Write-Output "goodbye!" | Out-Host    # works fine
    pause
}
} Finally {
    pause                     # works fine
    Write-output "goodbye!"   # not executed
}
} Finally {
    try{
        Write-Output "goodbye!" -ErrorAction Stop
    }catch{
        Write-Host "error caught"   # this is not executed.
    }                               # $error[0] after script execution is empty
    pause
}
} Finally {
    try{
        ThisCommandDoesNotExist
    }catch{
        Write-Host "error caught"   # this is executed
    }                               # $error[0] contains CommandNotFoundException      
    pause
}