c#执行命令行如命令提示符?

时间:2014-10-08 15:06:32

标签: c# command-line

我想编写一个c#代码来执行一些命令提示行,并将结果存储到c#中的全局变量中,以便在c#中的代码的其他部分进一步处理。

我买了一台设备并安装了它的驱动程序。我获取数据的唯一方法是在命令提示符下使用命令行。没有可用的API。但是,我想在c#中这样做,这就是我遇到麻烦的原因。

我有一些代码,但由于某些原因它不起作用。注意,我使用的参数input =“date”仅用于说明目的。我的工作不是使用“日期”,而是使用一些参数来获取数据。

static void Main(string[] args)
{
    System.Diagnostics.Process process = new System.Diagnostics.Process();
    System.Diagnostics.ProcessStartInfo startInfo = new System.Diagnostics.ProcessStartInfo();
    startInfo.WindowStyle = System.Diagnostics.ProcessWindowStyle.Hidden;
    // the cmd program
    startInfo.FileName = "cmd.exe";
    // set my arguments. date is just a dummy example. the real work isn't use date.
    startInfo.Arguments = "date";
    startInfo.RedirectStandardOutput = true;
    startInfo.UseShellExecute = false;
    process.StartInfo = startInfo;
    process.Start();
    // capture what is generated in command prompt
    var output = process.StandardOutput.ReadToEnd();
    // write output to console
    Console.WriteLine(output);
    process.WaitForExit();

    Console.Read();
}

感谢任何帮助。

2 个答案:

答案 0 :(得分:2)

我还猜测并非所有应用程序都正确使用stderr和stdout,因此您可以在"控制台应用程序"没有提供您期望的信息。

如果没有更多的重定向stderr,也会让你看看它是否与语法有关,而且应用程序正在抛出异常。

startInfo.RedirectStandardError = true;

我想补充一点,通过将其包装在一个类中,您可以与cmd shell进行交互,而不仅仅是运行并返回...如果您尝试静默自动化应用程序,这很可能是您的方法想...

我刚刚为VB中的一个人写了一个这样的例子,语法可能很粗糙,因为我多年没有启动过VB,但你得到了它的要点,应该能够很容易地在C#中复制。这是一个粗略的草案如何类型的方法,而不是我称之为生产准备的一段代码,教一个人去捕鱼样本;)

#Region " Imports "

Imports System.Threading
Imports System.ComponentModel

#End Region

Namespace Common

    Public Class CmdShell

#Region " Variables "

        Private WithEvents ShellProcess As Process

#End Region

#Region " Events "

        ''' <summary>
        ''' Event indicating an asyc read of the command process's StdOut pipe has occured.
        ''' </summary>
        Public Event DataReceived As EventHandler(Of CmdShellDataReceivedEventArgs)

#End Region

#Region " Public Methods "

        Public Sub New()
            ThreadPool.QueueUserWorkItem(AddressOf ShellLoop, Nothing)
            Do Until Not ShellProcess Is Nothing : Loop
        End Sub

        ''' <param name="Value">String value to write to the StdIn pipe of the command process, (CRLF not required).</param>
        Public Sub Write(ByVal value As String)
            ShellProcess.StandardInput.WriteLine(value)
        End Sub

#End Region

#Region " Private Methods "

        Private Sub ShellLoop(ByVal state As Object)
            Try
                Dim SI As New ProcessStartInfo("cmd.exe")
                With SI
                    .Arguments = "/k"
                    .RedirectStandardInput = True
                    .RedirectStandardOutput = True
                    .RedirectStandardError = True
                    .UseShellExecute = False
                    .CreateNoWindow = True
                    .WorkingDirectory = Environ("windir")
                End With
                Try
                    ShellProcess = Process.Start(SI)
                    With ShellProcess
                        .BeginOutputReadLine()
                        .BeginErrorReadLine()
                        .WaitForExit()
                    End With
                Catch ex As Exception
                    With ex
                        Trace.WriteLine(.Message)
                        Trace.WriteLine(.Source)
                        Trace.WriteLine(.StackTrace)
                    End With
                End Try
            Catch ex As Exception
                With ex
                    Trace.WriteLine(.Message)
                    Trace.WriteLine(.Source)
                    Trace.WriteLine(.StackTrace)
                End With
            End Try
        End Sub

        Private Sub ShellProcess_ErrorDataReceived(ByVal sender As Object, ByVal e As System.Diagnostics.DataReceivedEventArgs) Handles ShellProcess.ErrorDataReceived
            If Not e.Data Is Nothing Then RaiseEvent DataReceived(Me, New CmdShellDataReceivedEventArgs(e.Data))
        End Sub

        Private Sub ShellProcess_OutputDataReceived(ByVal sender As Object, ByVal e As System.Diagnostics.DataReceivedEventArgs) Handles ShellProcess.OutputDataReceived
            If Not e.Data Is Nothing Then RaiseEvent DataReceived(Me, New CmdShellDataReceivedEventArgs(e.Data & Environment.NewLine))
        End Sub

#End Region

    End Class

    <EditorBrowsable(EditorBrowsableState.Never)> _
       Public Class CmdShellDataReceivedEventArgs : Inherits EventArgs
        Private _Value As String

        Public Sub New(ByVal value As String)
            _Value = value
        End Sub

        Public ReadOnly Property Value() As String
            Get
                Return _Value
            End Get
        End Property

    End Class

End Namespace

为了确保没有陷阱,我继续在c#

中做了这个
 public class cmdShell
    {
        private Process shellProcess;

        public delegate void onDataHandler(cmdShell sender, string e);
        public event onDataHandler onData;

        public cmdShell()
        {
            try
            {
                shellProcess = new Process();
                ProcessStartInfo si = new ProcessStartInfo("cmd.exe");
                si.Arguments = "/k";
                si.RedirectStandardInput = true;
                si.RedirectStandardOutput = true;
                si.RedirectStandardError = true;
                si.UseShellExecute = false;
                si.CreateNoWindow = true;
                si.WorkingDirectory = Environment.GetEnvironmentVariable("windir");
                shellProcess.StartInfo = si;
                shellProcess.OutputDataReceived += shellProcess_OutputDataReceived;
                shellProcess.ErrorDataReceived += shellProcess_ErrorDataReceived;
                shellProcess.Start();
                shellProcess.BeginErrorReadLine();
                shellProcess.BeginOutputReadLine();
            }
            catch (Exception ex)
            {
                Trace.WriteLine(ex.Message);
            }
        }

        void shellProcess_ErrorDataReceived(object sender, DataReceivedEventArgs e)
        {
            doOnData(e.Data);
        }

        void shellProcess_OutputDataReceived(object sender, DataReceivedEventArgs e)
        {
            doOnData(e.Data);
        }

        private void doOnData(string data)
        {
            if (onData != null) onData(this, data);
        }

        public void write(string data)
        {
            try
            {
                shellProcess.StandardInput.WriteLine(data);
            }
            catch (Exception ex)
            {
                Trace.WriteLine(ex.Message);
            }
        }
    }

现在就像这样使用

cmdShell test = new cmdShell();
test.onData += test_onData;
test.write("ping 127.0.0.1");

有了这个地方

 void test_onData(cmdShell sender, string e)
        {
            Trace.WriteLine(e);
        }

您有一个完全交互式的cmd进程,可以从中写入和接收异步数据。

输出到窗口

C:\Windows>ping 127.0.0.1

Pinging 127.0.0.1 with 32 bytes of data:
Reply from 127.0.0.1: bytes=32 time<1ms TTL=128
Reply from 127.0.0.1: bytes=32 time<1ms TTL=128
Reply from 127.0.0.1: bytes=32 time<1ms TTL=128
Reply from 127.0.0.1: bytes=32 time<1ms TTL=128

Ping statistics for 127.0.0.1:
    Packets: Sent = 4, Received = 4, Lost = 0 (0% loss),
Approximate round trip times in milli-seconds:
    Minimum = 0ms, Maximum = 0ms, Average = 0ms

咖啡,睡觉......哈哈

如果你真的想要约会......

cmdShell test = new cmdShell();
test.onData += test_onData;
test.write("date");

产量

C:\Windows>date
The current date is: Wed 10/08/2014

    cmdShell test = new cmdShell();
    test.onData += test_onData;
    test.write("echo %date%");

产量

C:\Windows>echo %date%
Wed 10/08/2014

顺便说一下,如果你还没有实际使用过代码,这个方法会给出数据异步,这意味着 as 它传递给你的程序输出,所以如果你运行一个进程,需要时间,比如100 ping,traceroute等等......你看到它们发生的时候,不必等待它完成并返回。

此外,您可以在期间将命令传递回应用程序,例如取消,响应和更改语法,或者只是根据第一次运行的结果运行类似的其他内容。

基本上你可以像在cmd窗口中输入一样对待它,并在那里接收反馈,以正确的线程形式包装整个思考(从其他线程更新Windows控件时小心),你会有一个模拟cmd提示。

答案 1 :(得分:1)

您需要使用/ c date来让cmd像这样启动日期。

static void Main(string[] args)
{
    System.Diagnostics.Process process = new System.Diagnostics.Process();
    System.Diagnostics.ProcessStartInfo startInfo = new System.Diagnostics.ProcessStartInfo();
    startInfo.WindowStyle = System.Diagnostics.ProcessWindowStyle.Hidden;
    // the cmd program
    startInfo.FileName = "cmd.exe";
    // set my arguments. date is just a dummy example. the real work isn't use date.
    startInfo.Arguments = "/c date";
    startInfo.RedirectStandardOutput = true;
    startInfo.UseShellExecute = false;
    process.StartInfo = startInfo;
    process.Start();
    // capture what is generated in command prompt
    var output = process.StandardOutput.ReadToEnd();
    // write output to console
    Console.WriteLine(output);
    process.WaitForExit();

    Console.Read();
}

使用cmd.exe启动其他程序时,flags / c和/ k是您的朋友。 / c用于执行程序然后退出CMD。 / k用于执行程序,然后让CMD运行。