在同一进程中运行多个CMD命令

4

首先,一些背景信息。我编写了一个应用程序,可以与cmd.exe进行实时连接。

问题: 我想要多次写入而不关闭cmd.exe的进程。这会导致错误,因为在能够检索任何输出之前,我必须关闭StreamWriter,而在接收到输出后,我想再次写入它。

示例: 我想要使用命令cd C:\并接收更改路径的输出。之后,我想通过使用dir查看C:\目录中有哪些文件。 我不希望进程重新启动,因为它会重置路径。

我知道我可以简单地使用dir C:\,但这不是重点。 这只是一个简短的例子,我想用它来解决许多其他需要解决此问题的事情。

class Program
    {
        static void Main(string[] args)
        {
            ProcessStartInfo pInfo = new ProcessStartInfo();
            pInfo.RedirectStandardInput = true;
            pInfo.RedirectStandardOutput = true;
            pInfo.RedirectStandardError = true;
            pInfo.UseShellExecute = false;
            pInfo.CreateNoWindow = true;
            pInfo.FileName = "cmd.exe";

            Process p = new Process();
            p.StartInfo = pInfo;

            bool pStarted = false;

            Console.Write("Command: ");
            string command = Console.ReadLine();

            while (command != "exit")
            {
                if (!pStarted && command == "start")
                {
                    p.Start();
                    Console.WriteLine("Process started.");

                    pStarted = true;
                }
                else if (pStarted)
                {
                    StreamWriter sWriter = p.StandardInput;
                    if (sWriter.BaseStream.CanWrite)
                    {
                        sWriter.WriteLine(command);
                    }
                    sWriter.Close();

                    string output = p.StandardOutput.ReadToEnd();
                    string error = p.StandardError.ReadToEnd();

                    Console.WriteLine("\n" + output + "\n");
                }

                Console.Write("\nCommand: ");
                command = Console.ReadLine();
            }

            Console.WriteLine("Process terminated.");
            Console.ReadKey();
            }
    }

有人知道我如何保持一个进程并多次写入它,每次都接收输出吗?

提前致谢。

编辑:这可能与以下问题略有相似:使用.NET执行多个命令行的相同进程。链接的问题没有有用的答案,并且在多个方面不同。我面临的一个巨大问题是,我希望在用户发送每个命令后打印输出。


1
必须关闭StreamWriter - 为什么?使用事件(或单独的线程读/写)是与CMD通信的标准方式,应该可以很好地工作(假设您正在显示非常简化的代码)... - Alexei Levenkov
@EmpereurAiman 这个链接的问题还没有答案。 - Tamir Vered
但是你可以多次阅读和多次写入。 - BugFinder
捕获输出时机可以通过连接正确的事件来完成。点击这里查看(相当令人困惑的)示例。 - TaW
显示剩余2条评论
1个回答

1
您正在关闭流,不能简单地创建一个新流,因此:
  1. 在循环外声明sWriter
  2. 不要关闭流
不幸的是,您不能再使用ReadToEnd(),因为它会等待进程终止,而cmd不会。因此,您必须异步读取控制台输出。
这又会导致输出问题,因为您的输出“Command:”可能会干扰cmd的输出。
以下程序的异步版本应该解决您的基本问题,但会让您面临混合输出的问题:
using System;
using System.Diagnostics;
using System.IO;

namespace MultiConsole
{
    class Program
    {
        private static void Main()
        {
            var pInfo = new ProcessStartInfo
            {
                RedirectStandardInput = true,
                RedirectStandardOutput = true,
                RedirectStandardError = true,
                UseShellExecute = false,
                CreateNoWindow = false,
                FileName = "cmd.exe"
            };

            var p = new Process {StartInfo = pInfo};

            bool pStarted = false;

            Console.Write("Command: ");
            string command = Console.ReadLine();
            StreamWriter sWriter = null;
            while (command != "exit")
            {
                if (!pStarted && command == "start")
                {
                    p.Start();
                    sWriter = p.StandardInput;
                    pStarted = true;
                    ConsumeConsoleOutput(p.StandardOutput);
                    Console.WriteLine("Process started.");
                }
                else if (pStarted)
                {
                    if (sWriter.BaseStream.CanWrite)
                    {
                        sWriter.WriteLine(command);
                    }
                }

                Console.Write("\nCommand: ");
                command = Console.ReadLine();
            }

            if (sWriter != null) sWriter.Close();
            Console.WriteLine("Process terminated.");
            Console.ReadKey();
        }

        private static async void ConsumeConsoleOutput(TextReader reader)
        {
            var buffer = new char[1024];
            int cch;

            while ((cch = await reader.ReadAsync(buffer, 0, buffer.Length)) > 0)
            {
                Console.Write(new string(buffer, 0, cch));
            }
        }
    }
}

显然,在VS2010中无法使用“async”命名空间,因此我可能需要安装一些库才能使其正常工作。但非常感谢!这应该可以解决问题。 - Pieter Moens
@Shwasted:你不想使用2015社区版吗?它几乎拥有和2013专业版一样多的功能。 - Thomas Weller
首先,很抱歉回复晚了。在尝试运行您的代码时,我收到了一个错误:“'TextReader'不包含'ReadAsync'的定义,也没有接受类型为'TextReader'的第一个参数的扩展方法'ReadAsync'可以找到(您是否缺少使用指令或程序集引用?)”注意:我已经包含了您使用的所有库,并且我正在使用.NET Framework 4.5,因此根据https://msdn.microsoft.com/en-us/library/system.io.textreader.readasync%28v=vs.110%29.aspx应该是好的... - Pieter Moens
@Shwasted:我也在VS2013中尝试过,并将目标框架设置为4.5-它可以工作。你只需要两个引用:SystemSystem.Core - Thomas Weller
1
问题解决了...显然我是个白痴,在将我的VS2010项目转移到VS2015时,我没有将框架更改为4.5。 - Pieter Moens

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接