除非指定输出文件,否则 VBScript 的 Shell 命令将不会执行
VBScript's Shell Command Will Not Execute Unless An Output File Is Specified
我正在尝试 运行 shell 命令进行 google 语音识别。如果我向命令字符串提供输出文件,我只能 运行 命令 。
正如您在下面看到我的测试代码示例,如果提供了“>outputFile”,我会附上它,并且还在超时循环中编码以在设定时间限制。
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 分钟,然后超时并向我发送错误消息。
为什么它需要输出文件到 运行?
如果我在命令提示符下手动 运行 命令行,它 运行 完全没问题。
一旦 wshShellExec
在 WshRunning
情况下终止,而不是分配错误消息,应该分配输出。
Select Case wshShellExec.Status
Case WshRunning
wshShellExec.Terminate
TestFunction = "Terminated: " & vbcrlf & WshShellExec.StdOut.ReadAll()
Case WshFinished
TestFunction = "Finished: " & vbcrlf & WshShellExec.StdOut.ReadAll()
Case WshFailed
TestFunction = wshShellExec.StdErr.ReadAll()
End Select
输出缓冲区容量有限。如果您的命令向 stdout 写入过多文本,缓冲区将填满并阻止命令写入更多文本,直到您清除缓冲区(例如,通过读取缓冲区)。但是,ReadAll
不能用于此,因为该方法只会 return 在 命令完成后阻塞,否则会造成死锁。
您最好的选择是将输出重定向到一个或多个(临时)文件,并在命令完成后从这些文件中读取输出。
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
。
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
读取数据,因为如果错误输出过多,该缓冲区也可能会填满。但是,读取 both 缓冲区可能会创建 another 死锁,因为 IIRC ReadLine
阻塞直到它可以读取整行,所以如果脚本可能会挂起等待永远不会出现的错误输出。您可以使用 Read
而不是 ReadLine
来解决这个问题,但它仍然非常脆弱。
因此,最好的选择还是将命令输出重定向到文件,并在命令终止后读取这些文件。
我正在尝试 运行 shell 命令进行 google 语音识别。如果我向命令字符串提供输出文件,我只能 运行 命令 。
正如您在下面看到我的测试代码示例,如果提供了“>outputFile”,我会附上它,并且还在超时循环中编码以在设定时间限制。
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 分钟,然后超时并向我发送错误消息。
为什么它需要输出文件到 运行?
如果我在命令提示符下手动 运行 命令行,它 运行 完全没问题。
一旦 wshShellExec
在 WshRunning
情况下终止,而不是分配错误消息,应该分配输出。
Select Case wshShellExec.Status
Case WshRunning
wshShellExec.Terminate
TestFunction = "Terminated: " & vbcrlf & WshShellExec.StdOut.ReadAll()
Case WshFinished
TestFunction = "Finished: " & vbcrlf & WshShellExec.StdOut.ReadAll()
Case WshFailed
TestFunction = wshShellExec.StdErr.ReadAll()
End Select
输出缓冲区容量有限。如果您的命令向 stdout 写入过多文本,缓冲区将填满并阻止命令写入更多文本,直到您清除缓冲区(例如,通过读取缓冲区)。但是,ReadAll
不能用于此,因为该方法只会 return 在 命令完成后阻塞,否则会造成死锁。
您最好的选择是将输出重定向到一个或多个(临时)文件,并在命令完成后从这些文件中读取输出。
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
。
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
读取数据,因为如果错误输出过多,该缓冲区也可能会填满。但是,读取 both 缓冲区可能会创建 another 死锁,因为 IIRC ReadLine
阻塞直到它可以读取整行,所以如果脚本可能会挂起等待永远不会出现的错误输出。您可以使用 Read
而不是 ReadLine
来解决这个问题,但它仍然非常脆弱。
因此,最好的选择还是将命令输出重定向到文件,并在命令终止后读取这些文件。