【问题标题】:c# execute command line like command prompt?c# 像命令提示符一样执行命令行?
【发布时间】:2014-12-03 07:31:01
【问题描述】:

我想编写一个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();
}

感谢任何帮助。

【问题讨论】:

  • so that is why I am having trouble什么麻烦? “它不起作用”不是对问题的描述。它做什么?碰撞?报错?坍缩成奇点?什么都不做?您期望它会做什么?
  • 您的问题可能是date 本身会提示您输入新日期(从命令行尝试)。试试date /T,它将输出日期,而不需要你给它任何输入。或者,您可以只将enter 写入标准输入。

标签: c# command-line


【解决方案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();
}

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

【讨论】:

  • 对于date,您还需要date/T 标志,否则您需要将StandardInputWriteLine 重定向到它。
  • 谢谢。但代码仍然没有给出日期。它是空的。
  • 确实有效。日期可能有问题。我尝试了 ipconfig,它提供了数据。干得好。
  • 嗨..我如何传递多个参数?我需要浏览到一个目录并输入一个参数。我知道你可以做类似 process.start("cmd.exe", "arg1 arg2 arg3")
  • 我用类的 c# 等价物编辑了我以前的答案帖子。它使这个论点在很大程度上没有实际意义,因为它每次都会将整个命令链作为单个字符串传递,而不管语法如何......
【解决方案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提示符。

【讨论】:

  • 非常感谢您的回答!!!))))))它非常非常有用而且很棒!我有一个小问题:如何使用您的工具从“python.exe”之类的命令中获取输出?
  • 只要 python 在你的路径语句中,你应该能够像使用 cmd 提示符一样使用它。你想启动 python 并与之交互吗?或者您是否想将命令自动化到 python 并只查看输出?我无法从我所在的位置进行测试,但是如果它输出到 stderr 和 stdout,您应该能够将 cmd 替换为 python(或者如果不在路径中,则为 python 可执行文件的完整路径)我必须测试才能确定。我已经编写了一些应用程序,以这种方式自动安装随 CLR 一起安装的 .NET 编译器。
  • 我想通过 cmd.exe 自动使用 python.exe,但是我有一个问题。我无法获得 python stdout 和 stderror (((看起来我将它们重定向到我的应用程序,python 无法将它们自己获取输出和错误。如果我使用 python.exe 而不是 cmd.exe 运行进程,则此行为重复. 我认为,与流重定向有关的问题。
  • 我必须玩它才能确定,我敢打赌它会根据 python 的版本而有所不同。您能否让我知道您正在使用的确切版本的详细信息以及您正在尝试实现的示例,我会看看我能做什么。
  • Python 版本 2.7,但我认为,这与它的版本无关 :((。至于细节,我使用可执行文件“cmd.exe”创建进程并希望像我一样使用它Windows 控制台处于交互模式。因此,当我在交互模式下使用控制台时,我可以在发送命令后立即从中得到答案。我希望 python 在我的命令后立即返回结果,但现在我只能在python进程已退出。
猜你喜欢
  • 2011-10-26
  • 1970-01-01
  • 2017-09-18
  • 1970-01-01
  • 1970-01-01
  • 2013-08-01
  • 2017-02-28
  • 2012-11-23
  • 2010-11-30
相关资源
最近更新 更多