How to get Output of a Command Prompt Window line

2019-01-28 23:35发布

问题:

I am trying to get a command line output line by line till the end of the output but I am not able to do so. I am using it in my Form and this code executes on click of a button.
Can you tell me whats wrong with my code?

Dim proc As ProcessStartInfo = New ProcessStartInfo("cmd.exe")
    Dim pr As Process
    proc.CreateNoWindow = True
    proc.UseShellExecute = False
    proc.RedirectStandardInput = True
    proc.RedirectStandardOutput = True
    pr = Process.Start(proc)
    pr.StandardInput.WriteLine("cd C:\sdk\platform-tools\")
    pr.StandardInput.WriteLine("adb help")
    Dim helpArray(20) as String
    For i as Integer 1 To 7
    helpArray(i) = pr.StandardOutput.ReadLine()
    Next
    pr.StandardOutput.Close()

The program stops responding when this code is executed.

回答1:

I've done some research. adb help writes output into STDERR. So you need something like:

    Dim proc As ProcessStartInfo = New ProcessStartInfo("cmd.exe")
    Dim pr As Process
    proc.CreateNoWindow = True
    proc.UseShellExecute = False
    proc.RedirectStandardInput = True
    proc.RedirectStandardOutput = True
    pr = Process.Start(proc)
    pr.StandardInput.WriteLine("C:\sdk\platform-tools")
    pr.StandardInput.WriteLine("adb help 2>&1")
    pr.StandardInput.Close()
    Console.WriteLine(pr.StandardOutput.ReadToEnd())
    pr.StandardOutput.Close()

to catch it.
You need no 2>&1 if you call ipconfig, for example.



回答2:

Do not interate over the output and do not read it! Normally you don't know how long the output (same goes for error output too) would be, so you need to prepare for an unknown length. Since you are telling the Process class, that you want to handle the standard output and the standard error by yourself, you also need to bind to the events, in this case:

  • OutputDataReceived
  • ErrorDataReceived

or to block the current process and read the complete output at once like @Dmitry Kurilo does in his answer. I find the first approach better because I do not need to wait for the process to end to see it's output. The MSDN documentation of the ProcessStartInfo.RedirectstandardError property gives a good explanation of the different possibilities with a lot of examples. If you want to take a specific line, there are a lot of possibilities. One would be to store each output (line) in the delegate and use it later, using a List(Of String) and output the specific line when the process is done (= all output lines are present).

A possible solution could look like this:

' store error output lines
dim lines = new List(of String)

dim executable = "c:\temp\android\sdk\platform-tools\adb.exe"
dim arguments = " help"
dim process = new Process()
process.StartInfo = createStartInfo(executable, arguments)
process.EnableRaisingEvents = true
addhandler process.Exited, Sub (ByVal sender As Object, ByVal e As System.EventArgs) 
    Console.WriteLine(process.ExitTime)
    Console.WriteLine(". Processing done.")
    ' output line n when output is ready (= all lines are present)
    Console.WriteLine(lines(4))
end sub
' catch standard output
addhandler process.OutputDataReceived, Sub (ByVal sender As Object, ByVal e As System.Diagnostics.DataReceivedEventArgs) 
        if (not String.IsNullOrEmpty(e.Data))
            Console.WriteLine(String.Format("{0}> {1}", DateTime.Now.ToString("dd.MM.yyyy HH:mm:ss") ,e.Data))
        end if
end sub
' catch errors
addhandler process.ErrorDataReceived, Sub (ByVal sender As Object, ByVal e As System.Diagnostics.DataReceivedEventArgs) 
    'Console.WriteLine(String.Format("! {0}", e.Data))
    ' add every output line to the list of strings
    lines.Add(e.Data)
end sub
' start process
dim result = process.Start()
' and wait for output
process.BeginOutputReadLine()
' and wait for errors :-)
process.BeginErrorReadLine()

private function createStartInfo(byval executable as String, byval arguments as String) as ProcessStartInfo
    dim processStartInfo = new ProcessStartInfo(executable, arguments)
    processStartInfo.WorkingDirectory = Path.GetDirectoryName(executable)
    ' we want to read standard output
    processStartInfo.RedirectStandardOutput = true
    ' we want to read the standard error
    processStartInfo.RedirectStandardError = true
    processStartInfo.UseShellExecute = false
    processStartInfo.ErrorDialog = false
    processStartInfo.CreateNoWindow = true
    return processStartInfo
end function

Now even if the adb writes to the error output, you will be able to see it. It will also be complete.

The output in this case looks like this:

14.10.2014 12:49:10
. Processing done.
 -e                            - directs command to the only running emulator.

Another possibility would be to put everything into one string and after the process has finished split the single string on line endings (CRLF \r\n) and you will gain the lines you want to filter.



标签: vb.net cmd