找到了这个功能 http://www.cpearson.com/excel/ShellAndWait.aspx
但是还需要捕获shell输出的输出。任何代码建议?
答案 0 :(得分:44)
根据Andrew Lessard的回答,这里有一个运行命令并将输出作为字符串返回的函数 -
Public Function ShellRun(sCmd As String) As String
'Run a shell command, returning the output as a string
Dim oShell As Object
Set oShell = CreateObject("WScript.Shell")
'run command
Dim oExec As Object
Dim oOutput As Object
Set oExec = oShell.Exec(sCmd)
Set oOutput = oExec.StdOut
'handle the results as they are written to and read from the StdOut object
Dim s As String
Dim sLine As String
While Not oOutput.AtEndOfStream
sLine = oOutput.ReadLine
If sLine <> "" Then s = s & sLine & vbCrLf
Wend
ShellRun = s
End Function
用法:
MsgBox ShellRun("dir c:\")
答案 1 :(得分:20)
您可以CreateProcess
应用程序将其StdOut
重定向到管道,然后直接读取该管道; http://pastebin.com/CszKUpNS
dim resp as string
resp = redirect("cmd","/c dir")
resp = redirect("ipconfig","")
答案 2 :(得分:5)
您始终可以将shell输出重定向到文件,然后从文件中读取输出。
答案 3 :(得分:4)
基于bburns.km's answer,我在调用期间向可执行文件添加了传递输入(使用StdInput)。以防万一有人偶然发现并有同样的需求。
''' <summary>
''' Executes the given executable in a shell instance and returns the output produced
''' by it. If iStdInput is given, it is passed to the executable during execution.
''' Note: You must make sure to correctly enclose the executable path or any given
''' arguments in quotes (") if they contain spaces.
''' </summary>
''' <param name="iExecutablePath">
''' The full path to the executable (and its parameters). This string is passed to the
''' shell unaltered, so be sure to enclose it in quotes if it contains spaces.
''' </param>
''' <param name="iStdInput">
''' The (optional) input to pass to the executable. Default: Null
''' </param>
Public Function ExecuteAndReturnStdOutput(ByVal iExecutablePath As String, _
Optional ByVal iStdInput As String = vbNullString) _
As String
Dim strResult As String
Dim oShell As WshShell
Set oShell = New WshShell
Dim oExec As WshExec
Set oExec = oShell.Exec(iExecutablePath)
If iStdInput <> vbNullString Then
oExec.StdIn.Write iStdInput
oExec.StdIn.Close ' Close input stream to prevent deadlock
End If
strResult = oExec.StdOut.ReadAll
oExec.Terminate
ExecuteAndReturnStdOutput = strResult
End Function
注意:您需要添加对
Windows Script Host Object Model
的引用,以便了解WshShell
和WshExec
类型。
(要执行此操作,请转到VBA IDE菜单栏中的 Extras - &gt; 引用。)
答案 4 :(得分:3)
Sub StdOutTest()
Dim objShell As Object
Dim objWshScriptExec As Object
Dim objStdOut As Object
Dim rline As String
Dim strline As String
Set objShell = CreateObject("WScript.Shell")
Set objWshScriptExec = objShell.Exec("c:\temp\batfile.bat")
Set objStdOut = objWshScriptExec.StdOut
While Not objStdOut.AtEndOfStream
rline = objStdOut.ReadLine
If rline <> "" Then strline = strline & vbCrLf & CStr(Now) & ":" & Chr(9) & rline
' you can handle the results as they are written to and subsequently read from the StdOut object
Wend
MsgBox strline
'batfile.bat
'ping 1.1.1.1 -n 1 -w 2000 > nul
'echo 2
'ping 1.1.1.1 -n 1 -w 2000 > nul
'echo 4
'ping 1.1.1.1 -n 1 -w 2000 > nul
'echo 6
'ping 1.1.1.1 -n 1 -w 2000 > nul
'echo 8
End Sub
答案 5 :(得分:0)
此功能提供了使用剪贴板对象运行命令行命令的快速方法:
Function getCmdlineOutput(cmd As String)
CreateObject("WScript.Shell").Run "cmd /c """ & cmd & "|clip""", 0, True 'output>clipbrd
With CreateObject("New:{1C3B4210-F441-11CE-B9EA-00AA006B1A69}") 'latebound clipbrd obj
.GetFromClipboard 'get cmdline output from clipboard
getCmdlineOutput = .GetText(1) 'return clipboard contents
End With
End Function
Sub Demo1()
MsgBox getCmdlineOutput("w32tm /tz") 'returns the system Time Zone information
End Sub
它使用WShell Run
command是因为它可选地允许异步执行,这意味着它将在VBA继续之前等待命令完成运行,这在涉及剪贴板时很重要。
它还利用了一个内置的但经常被遗忘的命令行实用程序clip.exe
,在这种情况下,它是通过管道发送 cmdline 输出的目标。
剪贴板操作需要引用 Microsoft Forms 2.0 库,在这种情况下,我使用 Late-bound 引用创建了该库(自MS Forms以来,该引用看起来有所不同-aka fm20.dll
-是Windows库,而不是VBA。
在我的情况下,上面的功能会擦除现有剪贴板数据是一个问题,因此,下面的功能已被修改为保留并替换剪贴板上的现有文本。
如果剪贴板上除了文本以外还有其他内容,将会警告您它将丢失。一些沉重的编码可以允许返回其他/任何类型的剪贴板数据...但是高级剪贴板操作远比大多数用户意识到的复杂,而且我坦率地说没有必要或不希望进入。更多信息here。
请注意,此方法在MS Forms中是 Early-Bound ,但可以根据需要进行更改。 (但请记住,一般而言,后期绑定通常 double 处理时间。)
Function getCmdlineOutput2(cmd As String)
'requires Reference: C:\Windows\System32\FM20.DLL (MS Forms 2.0) [Early Bound]
Dim objClipboard As DataObject, strOrigClipbrd As Variant
Set objClipboard = New MSForms.DataObject 'create clipboard object
objClipboard.GetFromClipboard 'save existing clipboard text
If Not objClipboard.GetFormat(1) Then
MsgBox "Something other than text is on the clipboard.", 64, "Clipboard to be lost!"
Else
strOrigClipbrd = objClipboard.GetText(1)
End If
'shell to hidden commandline window, pipe output to clipboard, wait for finish
CreateObject("WScript.Shell").Run "cmd /c """ & cmd & "|clip""", 0, True
objClipboard.GetFromClipboard 'get cmdline output from clipboard
getCmdlineOutput2 = objClipboard.GetText(1) 'return clipboard contents
objClipboard.SetText strOrigClipbrd, 1 'Restore original clipboard text
objClipboard.PutInClipboard
End Function
Sub Demo2()
MsgBox getCmdlineOutput2("dir c:\") 'returns directory listing of C:\
End Sub
答案 6 :(得分:0)
基于各种答案(主要是Brian Burns的答案),这是经过测试和有效的简短版本:
Function F_shellExec(sCmd As String) As String
Dim oShell As New WshShell 'requires ref to Windows Script Host Object Model
F_shellExec = oShell.Exec(sCmd).StdOut.ReadAll
End Function
它工作得很好并且非常快。但是,如果输出太大(例如扫描整个C:驱动器sCmd = "DIR /S C:\"
),则ReadAll
将会崩溃
所以我想出了第二种解决方案,到目前为止,在两种情况下都可以正常工作。请注意,一读速度更快,并且如果它崩溃了,则读会从头开始重新启动,因此您不会错过任何信息
Function F_shellExec2(sCmd As String) As String
'Execute Windows Shell Commands
Dim oShell As New WshShell 'requires ref to Windows Script Host Object Model
'Dim oExec As WshExec 'not needed, but in case you need the type
Dim oOutput As TextStream
Dim sReturn As String
Dim iErr As Long
'Set oExec = oShell.Exec(sCmd) 'unused step, for the type
Set oOutput = oShell.Exec(sCmd).StdOut
On Error Resume Next
sReturn = oOutput.ReadAll
iErr = Err.Number
On Error GoTo 0
If iErr <> 0 Then
sReturn = ""
While Not oOutput.AtEndOfStream
sReturn = sReturn & oOutput.ReadLine & Chr(10)
Wend
End If
F_shellExec2 = sReturn
End Function