如何取消等待事件的Ctrl-C,而不是取消整个脚本在powershell



我在powershell中使用事件相关命令,当我注册一个对象事件并等待它时,我的脚本将被wait-event调用暂停。

根据文档,

The Wait-Event cmdlet suspends execution of a script or 
function until a particular event is raised. Execution 
resumes when the event is detected. 
To cancel the wait, press CTRL+C.

但是我发现的是,当我在powershell控制台按Ctrl-C时,整个脚本结束而不是wait-event调用,我认为wait-event调用可能返回$null值。

我不知道我的理解是否有问题,所以希望任何人都能分享更多的想法。

$port = New-Object System.IO.Ports.SerialPort COM5,115200,None,8,One
$port.Open()
$subscription = Register-ObjectEvent -InputObject $port -EventName DataReceived -SourceIdentifier "DataReceived"
while($true)
{
    $event = Wait-Event -SourceIdentifier "DataReceived"
    #
    # So how can I check if user press the Control-C to cancel wait-event
    #
    [System.IO.Ports.SerialPort]$sp = $event.Sender;
    $line = $sp.ReadExisting();
    Write-Host $event.EventIdentifier;
    Write-Host $line;
    Remove-Event -EventIdentifier $event.EventIdentifier;
}
Unregister-Event -SourceIdentifier "DataReceived"
$port.Close()

——编辑——

谢谢你的回答,但我想指出一些我已经尝试过的已知解决方案。

[console]::TreatControlCAsInput = $true
if ([console]::KeyAvailable)
{
    $key = [system.console]::readkey($true)
    if (($key.modifiers -band [consolemodifiers]"control") -and ($key.key -eq "C"))
    {
      "Terminating..."
      break
    }
}

这是解决常见Control-C场景的好方法,但问题是我的应用程序被wait-event调用暂停,所以我没有更改来检查键输入。

特别是,当我通过[console]::TreatControlCAsInput = $true为控制台启用Ctrl C时,Control-C将无法再取消Wait-Event,这也是一个问题。

这是一个很好的例子,你可以尝试一下(我重写了一个可用的测试):

$timer = New-Object System.Timers.Timer
[Console]::TreatControlCAsInput = $true;
$subscription = Register-ObjectEvent -InputObject $timer -EventName Elapsed -SourceIdentifier "TimeElapsed"
$event = Wait-Event -SourceIdentifier "DataReceived"
Write-Host "User Cancelled"
Unregister-Event -SubscriptionId $subscription.Id

您可以运行这个脚本,使用或不使用[Console]::....进行测试。

您可能必须调用[console]::TreatControlCAsInput = $true来告知(Ctrl+C)被视为普通输入,并使用类似循环中的语句:

if ([console]::KeyAvailable)
{
    $key = [system.console]::readkey($true)
    if (($key.modifiers -band [consolemodifiers]"control") -and ($key.key -eq "C"))
    {
      "Terminating..."
      break
    }
}

Wait-Event不处理Ctrl+C, PowerShell主机(控制台主机)通过停止脚本来处理Ctrl+C。

您可以使用Wait-Event指定超时时间,并在超时后检查是否有按键。试试以下命令:

$timer = New-Object System.Timers.Timer
$subscription = Register-ObjectEvent -InputObject $timer -EventName Elapsed -SourceIdentifier TimeElapsed
try
{
    $oldTreatControlCAsInput = [Console]::TreatControlCAsInput
    [Console]::TreatControlCAsInput = $true
    Write-Host -NoNewline "Waiting for event "
    do
    {
        $event = Wait-Event -SourceIdentifier DataReceived -Timeout 2
        if ($null -eq $event -and [Console]::KeyAvailable)
        {
            $key = [Console]::ReadKey($true)
            if ($key.KeyChar -eq 3)
            {
                Write-Host "Cancelled"
                break
            }
        }
        Write-Host -NoNewline "."
    } while ($null -eq $event)
}
finally
{
    [Console]::TreatControlCAsInput = $oldTreatControlCAsInput
    Unregister-Event -SourceIdentifier TimeElapsed
}

最小超时为1秒,因此您可能会看到Ctrl+C和循环停止之间的短暂延迟

相关内容

  • 没有找到相关文章

最新更新