c# - 执行多个命令行并输出

标签 c# cmd output

我想执行一些命令行来在每次输入后显示结果。

    Process p = new Process();
    ProcessStartInfo info = new ProcessStartInfo();
    info.FileName = "cmd.exe";
    info.RedirectStandardInput = true;
    info.UseShellExecute = false;
    p.StartInfo = info;
    p.Start();
    using (StreamWriter sw = p.StandardInput)
    {
        if (sw.BaseStream.CanWrite)
        {
            sw.WriteLine("ftp");
            //output
            sw.WriteLine("open ftp.server.com");
            //output
            sw.WriteLine("username");
            //output
            sw.WriteLine("password");
            //output
        }
    }

帮我理解如何在每个sw.WriteLine(...)之后生成输出结果?

已更新

它不能与 ftp 一起使用。为什么?

初始化:

Test test = new Test();
test.start();
Console.ReadKey();

测试:

class Test
    {    
        static StringBuilder StdOutput = new StringBuilder();
        Process p = null;
        Queue<string> cmdQueue = new Queue<string>();

        public void start(){

            cmdQueue = new Queue<string>();
            cmdQueue.Enqueue("cd c:\\");
            cmdQueue.Enqueue("dir");

            cmdQueue.Enqueue("ftp");
            cmdQueue.Enqueue("open us1.hostedftp.com");
            cmdQueue.Enqueue("<a href="https://stackoverflow.com/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="334900410a734a521d4146" rel="noreferrer noopener nofollow">[email protected]</a>");
            cmdQueue.Enqueue("123456");
            cmdQueue.Enqueue("dir");
            setupProcess();
            startProcess();    
        }

        private void setupProcess()
        {
            p = new Process();
            ProcessStartInfo info = new ProcessStartInfo();
            info.FileName = "cmd";
            info.CreateNoWindow = true;
            info.RedirectStandardOutput = true;
            info.RedirectStandardInput = true;
            info.UseShellExecute = false;

            p.OutputDataReceived += new DataReceivedEventHandler(OutputDataHandler);

            StdOutput = new StringBuilder();

            p.StartInfo = info;
        }

        private async void startProcess()
        {
            p.Start();    
            p.BeginOutputReadLine();                    

            using (StreamWriter sw = p.StandardInput)
            {

                if (sw.BaseStream.CanWrite)
                {
                    while (cmdQueue.Count > 0)
                    { 
                            string cmd = cmdQueue.Dequeue();

                            if (cmd != null & cmd != "")
                            {
                                await sw.WriteLineAsync(cmd);

                                Thread.Sleep(100);

                                //System.Console.WriteLine(StdOutput);
                            }
                            else
                            {
                                break;
                            }  
                    }

                    Console.WriteLine(StdOutput);    
                }                       
                p.WaitForExit();                    
            }
        }

        private static void OutputDataHandler(object sendingProcess, DataReceivedEventArgs outLine)
        {
            if (!String.IsNullOrEmpty(outLine.Data))
            {
                StdOutput.Append(Environment.NewLine + outLine.Data);    
                //System.Console.WriteLine(Environment.NewLine + outLine.Data);    
            }
        }
    }

最佳答案

我假设您实际上是在问如何从您想要在(一个)进程中执行的所有命令中捕获输出

这是我很久以前想出的解决方案的一个版本,当时我还是这里的菜鸟..

诀窍是通过监听收集输出,只要创建输出,Process就会触发以下事件:OutputDataReceived收到错误数据。我们需要异步运行才能使其工作,因此它看起来比通常的示例稍微复杂一点,通常的示例只有一个进程执行一个命令...:

首先是一些变量:

    Queue<string> cmdQueue = new Queue<string>();
    static StringBuilder StdOutput = new StringBuilder();
    static StringBuilder ErrOutput = new StringBuilder();

    Process p = null;
    Task processTask = null;
    bool processIsRunning = false;

这是一个按钮单击事件,它开始处理多行TextBox 中的所有命令。输出被收集在两个 StringBuilder 中;当队列为空时,我会等待更长的时间......:

private void button1_Click(object sender, EventArgs e)
{
    cmdQueue = new Queue<string>(tb_commands.Lines.ToList());

    setupProcess();
    startProcessTask();

    while (cmdQueue.Count > 0) Thread.Sleep(100);
    Thread.Sleep(500);
    tb_out.AppendText(StdOutput + "\r\n" + ErrOutput + "\r\n");
}

这是设置进程的例程。在这里,我们注册两个事件,当输出流中有行时,它们会通知我们......:

private void setupProcess()
{
    p = new Process();
    ProcessStartInfo info = new ProcessStartInfo();
    info.FileName = "cmd.exe";
    info.CreateNoWindow = true;
    info.RedirectStandardOutput = true;
    info.RedirectStandardError = true;
    info.RedirectStandardInput = true;
    info.UseShellExecute = false;

    p.OutputDataReceived += new DataReceivedEventHandler(OutputDataHandler);
    p.ErrorDataReceived += new DataReceivedEventHandler(ErrorDataHandler);
    StdOutput = new StringBuilder();
    ErrOutput = new StringBuilder();
    p.StartInfo = info;
}

设置完成后,我们可以启动一个任务,该任务将启动我们的进程异步..:

private void startProcessTask()
{
    var task = Task.Factory.StartNew(() => startProcess());
    processTask = task;
}

..最后是异步方法,在启动 Process 并从重定向流上的异步读取操作开始后,继续从命令队列中提供所有行。

private async void startProcess()
{
    try { p.Start(); processIsRunning = true; } catch
    {
        ErrOutput.Append("\r\nError starting cmd process.");
        processIsRunning = false;
    }

    p.BeginOutputReadLine();
    p.BeginErrorReadLine();

    using (StreamWriter sw = p.StandardInput)
    {

        if (sw.BaseStream.CanWrite)
            do
            {
                try
                {
                    string cmd = cmdQueue.Dequeue();
                    if (cmd != null & cmd != "") await sw.WriteLineAsync(cmd);
                } catch { }
            } while (processIsRunning);
        try { p.WaitForExit(); } catch { ErrOutput.Append("WaitForExit Error.\r\n"); }
    }
}

最后几部分是我们注册的两个事件,用于读取两个流的输出并将它们添加到StringBuilders:

private static void OutputDataHandler(object sendingProcess, DataReceivedEventArgs outLine)
{
    if (!String.IsNullOrEmpty(outLine.Data))
    {  
        StdOutput.Append(Environment.NewLine + outLine.Data);
    }
}

private static void ErrorDataHandler(object sendingProcess, DataReceivedEventArgs outLine)
{
    if (!String.IsNullOrEmpty(outLine.Data))
    {  
        ErrOutput.Append(Environment.NewLine + outLine.Data);
    }
}

请注意,这对于您可以输入到进程中的各种命令都适用,包括 FTP。在这里我更改我的代码页,显示我以前拥有的图像,登录到 FTP 服务器,调用帮助页面,cd 和 dir,下载图像,关闭连接并检查我现在拥有的图像..:

enter image description here

一个警告:我写这篇文章的方式一定有问题,因为 VS 一直提示 System.InvalidOperationException 并且 exe 文件占用了约 10% 的 cpu 。帮助我将非常感激..

关于c# - 执行多个命令行并输出,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30788688/

相关文章:

c# - Windows azure应用程序开发步骤失败

c# - 匿名类的返回类型是什么

powershell - 具有延迟变量扩展的 For 循环中 "!"文字问题的解决方法

windows - SETX 不会将路径附加到系统路径变量

windows - 通过进程 ID 查找进程名称

python - 如何创建一个Python脚本来制作多个bash脚本?

c - Printf 和 scanf 要求输入。 BST 的循环错误

c# - 使用正则表达式删除长文本中字符附近的空格

c# - 从连接池的角度来看,我做错了什么吗?

java - 如何将 java 控制台输出中的所有 java 行保存到文本文件并正确附加它?