使用自动热键捕获CMD输出

使用自动热键捕获CMD输出,cmd,autohotkey,Cmd,Autohotkey,我正在尝试用自动热键读取Windows CMD的标准输出。例如,我希望将setconsole命令的输出存储在变量中的AHK中。我不久前就已经实现了,这让我更加困惑,为什么它现在不起作用。 在AHK论坛中,有一个关于CMDret的网站,这是一个基于DLL的功能,可以完全满足我的需求。第一个问题是找到一个有效的下载,因为帖子中的所有链接都没有了。谷歌给了我,托管v3.1.2。虽然似乎有一个较新的版本(v3.2.1分别4d Beta),但我检查了它并测试了一个简单的示例: msgbox % CMDre

我正在尝试用自动热键读取Windows CMD的标准输出。例如,我希望将
set
console命令的输出存储在变量中的AHK中。我不久前就已经实现了,这让我更加困惑,为什么它现在不起作用。
在AHK论坛中,有一个关于CMDret的网站,这是一个基于DLL的功能,可以完全满足我的需求。第一个问题是找到一个有效的下载,因为帖子中的所有链接都没有了。谷歌给了我,托管v3.1.2。虽然似乎有一个较新的版本(v3.2.1分别4d Beta),但我检查了它并测试了一个简单的示例:

msgbox % CMDret(COMSPEC " /C set")
CMDret(CMD) 
{ 
  VarSetCapacity(StrOut, 10000) 
  RetVal := DllCall("cmdret.dll\RunReturn", "str", CMD, "str", StrOut)
  Return, %StrOut%
}
不幸的是,MsgBox没有包含任何内容。然后我检查了
RetVal
,它的值为0;随附自述说明如下:

如果函数失败,则返回值为零

再往下看,它说:

注意:当前只有32位的控制台应用程序可以与 此CMDret的dll版本(v3.1.2或更低版本)。需要 command.com可能不会产生任何输出,并且可能会崩溃。避 我已经在下载中包含了一个名为“cmdstub.exe”的文件(在 Win9x文件夹)。调用16位时应使用此文件 控制台应用程序以启用返回的输出

总之,我不确定问题出在哪里。我的机器是64位的。但是自述文件中的相应条款应该只排除16位系统,还是只包括32位系统?
如果计算架构可能不是问题所在,那么会是什么呢

我要找的是以下任一项:

  • 我可以修复这个问题并继续使用v3.1.2吗
  • 有没有人能为我提供一个新版本的工作源(甚至是本地副本)
  • 是否有其他方法[库、.ahk代码等]可供我使用?(最好类似,因为CMDret看起来非常简单)

  • 我在以下位置找到了适用于64位自动热键的纯脚本解决方案:


    在玩了一会儿之后,我能够捕获我使用DOS Type命令列出的40k文本文件的整个输出。有一个演示演示了如何与time命令交互,如果您需要与dos命令或批处理脚本进行有限的双向交互,这很好。

    如果您不需要实时输出,您可以使用cmd框本身保存自己的文本文件,然后在控制台的PID完成时使用自动热键检测(使用
    runwait
    的返回结果,并将输出的文件读入内存

    因此,您可以在run命令中执行此操作(只是一个常规cmd参数):

    现在您有了一个包含ipconfig输出的文本文件

    或 您也可以执行相同的操作,但不必输出到文本文件,而是可以输出到剪贴板,如下所示:

    ipconfig | clip
    

    然后,由于输出在剪贴板上,您可以轻松地将其抓取到自动热键中。

    这个脚本怎么样,
    stdoutovar

    它支持64位控制台。

    这已经困扰了我一段时间了——最后终于奏效了

    唯一的先决条件是MS sqlcmd.exe,一个名为AHK_Dev的数据库 当然,当你想利用它的时候,可以让DBA读取这个值

    请确保用自己的值替换{yourDir}和{yourServer}

    USE AHK_DEV
    CREATE TABLE [dbo].[AHK_DOS]([dos_out] [varchar](max) NULL) ON [PRIMARY];
    insert into ahk_dos select 'empty'
    
    创建以下脚本…将其命名为dos_out.bat

    @echo off
    if "%1" == "" ( 
        set v_cmd=""
    ) else (
        set v_cmd=%1
    )
    set v_cmd=%v_cmd:~1,-1%
    SETLOCAL ENABLEDELAYEDEXPANSION
    if "!v_cmd!" == "" (
        set v_cmd="echo ... %COMPUTERNAME% %USERNAME% %DATE% %TIME%"
        set v_cmd=!v_cmd:~1,-1!
    )
    set v_data=""
    FOR /F "usebackq delims=¬" %%i in (`!v_cmd!`) do (
        set v_data="!v_data:~1,-1!%%i~"
    )
    set q_cmd="set nocount on;update ahk_dos set dos_out=N'!v_data:~1,-1!'"
    "{yourDir}\Microsoft SQL Server\90\Tools\Binn\sqlcmd.exe" -S {yourServer} -E -d ahk_dev -Q !q_cmd! -W 
    set q_cmd="set nocount on;select len(dos_out) as out_len, dos_out from ahk_dos"
    "{yourDir}\Microsoft SQL Server\90\Tools\Binn\sqlcmd.exe" -S {yourServer} -E -d ahk_dev -Q !q_cmd! -W -w 8000
    pause
    
    您可以使用从AHK运行它

    dosCmd2db(c) {
    runwait, {yourDir\}dos_out.bat "%c%", , , dospid
    msgbox %dospid% closed
    }
    dosCmd2db("")
    dosCmd2db("echo This is a test")
    dosCmd2db("dir")
    
    由于同一字段每次都在更新,您显然需要在每个字段之间做一些事情,以使此示例有用

    试试看,让我知道你进展如何


    关于这一点,自2019年11月起,杰夫新推荐了两种方法:

    如何检索命令行操作的输出? 测试表明,由于文件缓存,临时文件的输出相对较小,速度可能非常快。事实上,如果文件在使用后立即删除,通常不会写入磁盘。例如:

    RunWait %ComSpec% /c dir > C:\My Temp File.txt
    FileRead, VarToContainContents, C:\My Temp File.txt
    FileDelete, C:\My Temp File.txt
    
    <>避免使用临时文件(特别是如果输出较大),请考虑使用 方法,如Run命令示例所示

    Run命令的示例-:

    注意:后一种方法(shell.Exec)将导致cmd窗口的快速显示。 您可以通过将这些行放在脚本顶部来缩短其出现的持续时间,这也会导致闪烁仅在您第一次调用cmd命令时发生一次。从:


    同时,我也发现了这个问题。不幸的是,它总是会产生一个窗口,我想避免出现这种情况,特别是因为我使用诸如密码之类的敏感数据调用实用程序。我在这里也看到了一个安全问题。因为我在处理敏感数据,我不希望我的密码显示在文件或剪贴板中。此外,我需要能够实时捕获流。我认为使用这些方法会相当复杂。当然,你必须在脚本中处理它。如果它是敏感的,那么你不能使用剪贴板,因为可能有其他东西在跟踪它。但是,如果你输出到一个文本文件,并将文件加载到内存中,那么你可以删除该文件xt文件并将其删除。我在自己的一些应用程序中这样做,它就像一个符咒一样工作。只需要三到四行自动热键代码就可以完成。文件也可以通过任何其他进程访问。当然,文件不存在很长时间,可能我有点偏执,但仍然有一个我不想接受的机会。特别是因为HK只删除文件,这不会使数据无法读取。Hmmm…如果在删除之前删除内容(使用
    fileopen
    )。这太棒了!我正在使用此命令将我的WAN IP地址保存到一个变量中:
    nslookup myip.opendns.com resolver1.opendns.com | find/I“address”|
    
    RunWait %ComSpec% /c dir > C:\My Temp File.txt
    FileRead, VarToContainContents, C:\My Temp File.txt
    FileDelete, C:\My Temp File.txt
    
    MsgBox % RunWaitOne("dir " A_ScriptDir)
    
    
    RunWaitOne(command) {
        shell := ComObjCreate("WScript.Shell")
        exec := shell.Exec(ComSpec " /C " command)
        return exec.StdOut.ReadAll()
    }
    
    ;Following 2 lines : the cmd window will flash only once and quickly
    DllCall("AllocConsole")
    WinHide % "ahk_id " DllCall("GetConsoleWindow", "ptr")