Команда оболочки VBScript не будет выполняться, если не указан выходной файл - PullRequest
0 голосов
/ 01 февраля 2019

Я пытаюсь запустить команду оболочки для распознавания речи 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 минут, прежде чем истечет время ожидания и отправит мне сообщение об ошибке.Зачем ему нужен выходной файл для запуска?Если я запускаю командную строку вручную из командной строки, она отлично работает.

Ответы [ 2 ]

0 голосов
/ 01 февраля 2019

Выходные буферы имеют ограниченную емкость.Если ваша команда записывает слишком много текста для вывода, буфер заполнится и заблокирует команду на дальнейшую запись, пока вы не очистите буфер (например, прочитав его).ReadAll не может использоваться для этого, хотя, потому что этот метод возвратит только после , команда завершилась и блокирует в противном случае, таким образом создавая тупик.

Ваш лучший вариант -перенаправьте вывод в один или несколько (временных) файлов и прочитайте вывод из этих файлов после завершения команды.

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, поскольку этот буфер может также заполниться, если выводится слишком много ошибок.Однако чтение обоих буферов может создать еще один тупик, поскольку IIRC ReadLine блокируется до тех пор, пока не сможет прочитать полную строку, поэтому, если сценарий может зависнуть, ожидая вывода ошибок, которые никогда не появляются.Возможно, вам удастся обойти это, используя Read вместо ReadLine, но это все равно будет очень хрупким.

Итак, опять же, ваш лучший вариант - перенаправить вывод команды в файлы и прочитатьэти файлы после завершения команды.

0 голосов
/ 01 февраля 2019

Как только 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
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...