问题描述
我正在尝试运行Shell命令进行Google语音识别。如果我将输出文件提供给命令字符串,则只能运行命令 。
I'm trying to run a shell command for google speech recognition. I'm able to run the command only if I provide an output file to the command string.
如您所见,我的测试代码示例在下面的代码中,如果提供了> outputFile ,并且在超时循环中进行了编码,以在设置的时间限制后中止该过程,则我将附加> outputFile 。
As you can see my test code sample below, I would attach the ">outputFile" if one is provided and also coded in a timeout loop to abort the process after a set time limit.
strCommand = "cmd /c ipconfig /all"
If outputFile <> "" Then
strCommand = strCommand & " > """ & outputFile & """"
End If
Set wshShellExec = wshShell.Exec(strCommand)
expiration = DateAdd("s", 600, Now)
Do While wshShellExec.Status = WshRunning And Now < expiration
WScript.Sleep 5000
Loop
Select Case wshShellExec.Status
Case WshRunning
wshShellExec.Terminate
TestFunction = "{""error"": ""TestFunction Command Timed Out""}"
Case WshFinished
TestFunction = WshShellExec.StdOut.ReadAll()
Case WshFailed
TestFunction = wshShellExec.StdErr.ReadAll()
End Select
如果我离开 outputFile
清空并尝试从该函数返回输出,它所做的只是静止5分钟,然后超时并向我发送我的错误消息。
为什么需要输出文件才能运行?
如果我在命令提示符上手动运行命令行,它运行得很好。
If I leave outputFile
empty and try to expect the output to be returned from the function, all it does is sit still for 5 minutes before timing out and sending me my error message.Why does it need an output file to run?If I run the command line manually on a Command Prompt, it runs perfectly fine.
推荐答案
输出缓冲区有限容量。如果您的命令写了太多文本无法输出,则缓冲区将填满并阻止命令继续写入,直到您清除缓冲区为止(例如通过读取缓冲区)。但是, ReadAll
不能用于此目的,因为该方法仅在命令完成后返回 ,否则将阻塞,从而造成死锁
Output buffers have limited capacity. If your command writes too much text to stdout the buffer will fill up and block the command from writing more until you clear the buffer (e.g. by reading from it). ReadAll
can't be used for that, though, because that method will only return after the command has finished and block otherwise, thus creating a deadlock.
您最好的选择是将输出重定向到一个或多个(临时)文件,并在命令完成后读取这些文件的输出。
Your best option is to redirect output to one or more (temp) files, and read the output from those files after the command has finished.
outfile = "C:\out.txt"
errfile = "C:\err.txt"
cmd = "cmd /c ipconfig /all >""" & outfile & """ 2>""" & errfile & """"
timeout = DateAdd("s", 600, Now)
Set sh = CreateObject("WScript.Shell")
Set ex = sh.Exec(cmd)
Do While ex.Status = WshRunning And Now < timeout
WScript.Sleep 200
Loop
Set fso = CreateObject("Scripting.FileSystemObject")
outtxt = fso.OpenTextFile(outfile).ReadAll
errtxt = fso.OpenTextFile(errfile).ReadAll
如果您不想这样做由于某些原因,您必须反复阅读 StdOut
。
If you don't want to do that for some reason you must read from StdOut
repeatedly.
outtxt = ""
errtxt = ""
cmd = "ipconfig /all"
timeout = DateAdd("s", 600, Now)
Set sh = CreateObject("WScript.Shell")
Set ex = sh.Exec(cmd)
Do While ex.Status = WshRunning And Now < timeout
WScript.Sleep 200
outtxt = outtxt & ex.StdOut.ReadLine & vbNewLine
Loop
请注意,您可能还需要阅读 StdErr
,因为如果错误输出过多,该缓冲区也可能会填满。但是,读取两个缓冲区都可能导致另一个死锁,因为IIRC ReadLine
块会一直阻塞,直到可以读取整行为止,因此如果脚本可能挂起,等待从未出现的错误输出。您也许可以通过使用 Read
而不是 ReadLine
来解决此问题,但它仍然非常脆弱。
Note that you may also need to read from StdErr
, because that buffer might fill up too if there is too much error output. However, reading both buffers might create another deadlock, because IIRC ReadLine
blocks until it can read a full line, so if the script might hang waiting for error output that never appears. You might be able to work around that by using Read
instead of ReadLine
, but it'll still be very fragile.
同样,最好的选择是将命令输出重定向到文件,并在命令终止后读取这些文件。
So, again, your best option is to redirect command output to files and read those files after the command terminates.
这篇关于除非指定了输出文件,否则VBScript的Shell命令将不会执行的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!