【问题标题】:Get Ctrl-C to work better on invoke-expression for powershell?让 Ctrl-C 在 powershell 的调用表达式上更好地工作?
【发布时间】:2022-01-27 04:57:41
【问题描述】:

我正在执行一个用 C++ 编写的旧控制台命令的调用表达式,并且我无法控制 C++ 源代码...但是,我认为它会捕获 Ctrl-C 以阻止命令行打断它...因此,当我从我的 powershell 脚本调用表达式时,无法使用 ctrl-C 中断执行,它会锁定我的终端,我需要继续杀死并重新启动我的终端窗口...这非常烦人...

在使用invoke-expression启动C++程序时,有没有办法确保powershell获取ctrl-C而不是C++程序? 就像也许,我可以拒绝将标准输入提供给 C++ 程序,而让 powershell 拥有它?或者也许有一些解决方案,标准输入转到另一个等待 ctrl-c 然后杀死调用表达式线程的 powershell 线程。..

例子:

PS> $cmd = <path_to_misbehaving_cpp_program_that_doesnt_Allow_ctrl_c_To_break_it>

PS> invoke-expression $cmd
# now here if I ctrl-C I can't break out of the invoke-expression....
# But I need this capability to ctrl-C
#  to break the script and terminate the
#  invoke expression of the C++ program.

【问题讨论】:

  • 在 Powershell ISE 中是否可以使用停止按钮(红色方块)?
  • 有趣的想法,但它需要从标准的 powershell 窗口运行......除非这能帮助您理解问题?
  • Start-Process 做另一个线程并在需要时终止进程?
  • 您需要能够在应用程序输出时使用它,还是只需要在您按下 Ctrl+C 之前安静地运行?
  • 顺便说一句:Invoke-Expression (iex) should generally be avoided;绝对don't use it to invoke an external program or PowerShell script。如果您的可执行路径(仅)存储在$cmd 中,只需使用&amp; $cmd 调用它

标签: powershell


【解决方案1】:

在 powershell 中启动和停止(终止)进程:

使用Start-Process cmdlet 启动其他程序。如果您使用-PassThru 开关,您将返回信息女巫进程已启动。

$Proc = Start-Process powershell.exe -ArgumentList '-command "sleep 60" '  -PassThru

这个进程很容易被 Stop-Process 杀死,即使它应该再运行 60 秒:

$Proc | Stop-Process

编辑:

现在带有退出代码(Thx @mklement0 for the Wait

$Proc.WaitForExit()
$Proc.ExitCode

【讨论】:

  • 如何从进程中获取退出码?
  • @pico: $Proc.WaitForExit(); $Proc.ExitCode
  • -NoNewWindow 传递给Start-Process 可能是个好主意,这样进程的输出就会出现在当前控制台窗口中,而不是创建一个新窗口。
  • @zett42 可以,但可能会让人分心。当您要倾倒的窗口中不断出现东西时,很难终止该过程:$Proc = start-process powershell.exe -ArgumentList '-command "1..60 | % {sleep 1;$_}" ' -PassThru -NoNewWindow
  • 您可能希望try {$proc = ...; while($true){Write-Host "Still running..."; Start-Sleep 2}}finally{$proc|Stop-Process -Force; $proc.ExitCode} 使用 Ctrl+C 的“自清洁”解决方案
【解决方案2】:

让它响应 ctrl-c 的技巧是通过管道 $null 到通过 start-process powershell 运行的命令中...见下文...另外,请注意最后的“kill -force”杀死从最初的 powershell.exe 进程开始剩余的子进程......我的程序创建了在 ctrl-c kill powershell.exe 之后继续运行的子进程,所以我需要再次杀死......杀死整个进程树。

$script:Proc             = $null

# Run Command as a separate process
function x1_process {
    
    write-host "`nx1_process: $args"
                
    $posh = (get-command powershell.exe).Source

    $iproc = Start-Process $posh -ArgumentList "`$null `| $args" -PassThru -NoNewWindow 
    $script:Proc = $iproc

    if ($iproc -eq $null) {
        throw "null proc"       
    }
    
    Wait-Process -InputObject $iproc

    $code = $iproc.ExitCode
    if ($code -ne 0) {
        throw "return-code:$code"
    }   
    
    write-host "ok`n"
    return
}

try {
    x1_process mycommand.exe arg1 arg2 ...
}
finally {
    if ($script:Proc) {
        if (-not $script:Proc.HasExited) {
            write-host -ForegroundColor Red "=> Killing X1_PROCESS <="
            Stop-Process -InputObject $script:Proc -Force -ErrorAction SilentlyContinue
        }
    }
}

【讨论】:

  • Stop-Process not 杀死进程 tree - 请参阅 github.com/PowerShell/PowerShell/blob/…
  • 虽然将$null 传递到外部程序 以提供空标准输入 确实有效,但为了概念清晰,我推荐@(),因为它也适用于 PowerShell 命令
  • Start-Processpowershell.exe-ArgumentList "`$null `| $args" 一起使用是脆弱的 - 它会因包含空格和其他元字符的参数而失败。
  • 如果使 Ctrl-C 与您的外部程序一起工作的关键是提供无标准输入,您可以尝试使用@987654329 直接调用 @
猜你喜欢
  • 2011-10-16
  • 1970-01-01
  • 2012-01-29
  • 1970-01-01
  • 2018-06-28
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多