Powershell 最后块用 Ctrl-C 跳过
Powershell Finally block skipped with Ctrl-C
我正在使用 Try/Finally 在 Powershell 中编写一个监控脚本,以便在脚本结束时记录一条消息。该脚本旨在无限期地 运行,所以我想要一种方法来跟踪意外退出。
所有其他 Whosebug post 和 Help page 我已经检查过以下状态:
A Finally block runs even if you use CTRL+C to stop the script. A Finally block also runs if an Exit keyword stops the script from within a Catch block.
在实践中,我没有发现这是真的。我正在使用以下人为设计的示例来对此进行测试:
Try {
While($True) {
echo "looping"
Start-Sleep 3
}
} Finally {
echo "goodbye!"
pause
}
这里的Finally
块在每次Ctrl+C之后都会跳过(没有回显,没有停顿),当 运行ning 作为保存的脚本或通过内置的 Powershell ISE 执行时。我得到的唯一输出是:
looping
looping
...(repeat until Ctrl-C)
我显然漏掉了什么,但我不知道它是什么,尤其是在这么小的代码片段中。
功能代码
这会给你我相信你想要的行为:
Try {
While($True) {
echo "looping"
Start-Sleep 3
}
} Finally {
Write-Host "goodbye!"
pause
}
参考资料
Sends the specified objects to the next command in the pipeline. If the command is the last command in the pipeline, the objects are displayed in the console.
Writes customized output to a host.
Try-Catch-Finally - Syntax note
Note that pressing CTRL+C stops the pipeline. Objects that are sent to the pipeline will not be displayed as output. Therefore, if you include a statement to be displayed, such as "Finally block has run", it will not be displayed after you press CTRL+C, even if the Finally block ran.
说明
根据 TheIncorrigible1 的评论和 Vesper 的回答,关键是管道停止。但这并不是因为 Write-Output
中的错误。而且我认为它本身并不是一个令人满意的解释。
- "If the command is the last command in the pipeline, the objects are displayed in the console." - 在 finally 块中出现此语句是错误的。但是,显式传递给
Out-Host
将产生所需的输出。
- 关于 Try-Catch-Finally 注释
- 引用的部分令人困惑,因为它适用于 未处理的对象 发送到管道。
- 发送到管道并在
Finally
块内处理的对象没问题。
- 它谈论 "even if the Finally block has ran" 但
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
}
正确的答案是 Ctrl+C 中断管道,如 link 中所述,并且 echo
使用管道来处理它的输出。因此,一旦您 Ctrl+C,写入管道会导致脚本块出错,并且不会处理任何进一步的命令。因此,不要使用直接将输出发送到 stdout 的命令,并且有很多间接使用管道的命令。另一方面,Write-Host
不使用管道,因此不会引发错误。
我正在使用 Try/Finally 在 Powershell 中编写一个监控脚本,以便在脚本结束时记录一条消息。该脚本旨在无限期地 运行,所以我想要一种方法来跟踪意外退出。
所有其他 Whosebug post 和 Help page 我已经检查过以下状态:
A Finally block runs even if you use CTRL+C to stop the script. A Finally block also runs if an Exit keyword stops the script from within a Catch block.
在实践中,我没有发现这是真的。我正在使用以下人为设计的示例来对此进行测试:
Try {
While($True) {
echo "looping"
Start-Sleep 3
}
} Finally {
echo "goodbye!"
pause
}
这里的Finally
块在每次Ctrl+C之后都会跳过(没有回显,没有停顿),当 运行ning 作为保存的脚本或通过内置的 Powershell ISE 执行时。我得到的唯一输出是:
looping
looping
...(repeat until Ctrl-C)
我显然漏掉了什么,但我不知道它是什么,尤其是在这么小的代码片段中。
功能代码
这会给你我相信你想要的行为:
Try {
While($True) {
echo "looping"
Start-Sleep 3
}
} Finally {
Write-Host "goodbye!"
pause
}
参考资料
Sends the specified objects to the next command in the pipeline. If the command is the last command in the pipeline, the objects are displayed in the console.
Writes customized output to a host.
Try-Catch-Finally - Syntax note
Note that pressing CTRL+C stops the pipeline. Objects that are sent to the pipeline will not be displayed as output. Therefore, if you include a statement to be displayed, such as "Finally block has run", it will not be displayed after you press CTRL+C, even if the Finally block ran.
说明
根据 TheIncorrigible1 的评论和 Vesper 的回答,关键是管道停止。但这并不是因为 Write-Output
中的错误。而且我认为它本身并不是一个令人满意的解释。
- "If the command is the last command in the pipeline, the objects are displayed in the console." - 在 finally 块中出现此语句是错误的。但是,显式传递给
Out-Host
将产生所需的输出。 - 关于 Try-Catch-Finally 注释
- 引用的部分令人困惑,因为它适用于 未处理的对象 发送到管道。
- 发送到管道并在
Finally
块内处理的对象没问题。 - 它谈论 "even if the Finally block has ran" 但
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
}
正确的答案是 Ctrl+C 中断管道,如 link 中所述,并且 echo
使用管道来处理它的输出。因此,一旦您 Ctrl+C,写入管道会导致脚本块出错,并且不会处理任何进一步的命令。因此,不要使用直接将输出发送到 stdout 的命令,并且有很多间接使用管道的命令。另一方面,Write-Host
不使用管道,因此不会引发错误。