【问题标题】:C# StandardOutput hangs, how can I detect it's waiting for input?C# StandardOutput 挂起,我如何检测它正在等待输入?
【发布时间】:2015-07-01 23:14:11
【问题描述】:

我一直在使用 C# 处理流程(使用 Process 和 ProcessStartInfo)。现在,只有一个问题真正困扰着我,但仍未找到解决方法。

当应用程序“等待”某些输入时,StandardOutput 将挂起。 这意味着,如果您使用 ReadToEnd,它将永远不会返回(因为实际的输入窗口是不可见的)。

现在,当我使用 StandardInput 提供输入时,这会产生问题。例如:

  1. 使用 C# 启动进程
  2. 使用 StandardInput 输入命令。
  3. 开始读取输出流。
  4. 根据最后一个输出运行另一个。

现在这就是问题所在:我无法判断进程是在等待输入还是仍在生成输入,因为我的进程“卡住”了从 StandardOutput 读取数据(它在同一个线程上完成)。

我需要在我的命令运行后读取输出,运行一些算法,然后根据之前的命令输出运行另一个命令。

是否有任何方法可以检测正在运行的进程是否已完成加载我的命令并等待新输入?和 cmd 一样吗?

【问题讨论】:

    标签: c# process cmd


    【解决方案1】:

    试图跟随彼得的回答,我没有在 StandardOutput 的末尾找到任何特殊的分隔符(我也检查了 ErrorOutput)。

    通过我的思考,为什么不使用 echo 来“模拟”分隔符?所以我提出了这段代码,它允许我运行一个特定的命令并立即在同一个线程上获得输出:

        /// <summary>
        /// A string used to write into the bash and allows us to detect when the bash finished to write it's output.
        /// </summary>
        const string delimiterString = "#WAITING";
    
        /// <summary>
        /// Runs the specified command and return it's output.
        /// </summary>
        /// <param name="command"></param>
        /// <returns></returns>
        public string RunCommand(string command)
        {
            sessionProcess.StandardInput.WriteLine(command);
    
            // Add a special string to be recognized when output is waiting
            sessionProcess.StandardInput.WriteLine("echo \"" + delimiterString + "\"");
    
            string output = "";
            int lastChr = 0;
    
            do
            {
                lastChr = sessionProcess.StandardOutput.Read();
    
                string outputChr = null;
                outputChr += sessionProcess.StandardOutput.CurrentEncoding.GetString(new byte[] { (byte)lastChr });
                output += outputChr;
    
                if (output.EndsWith(delimiterString))
                {
                    // Remove delimeter
                    output = output.Replace(Environment.NewLine + delimiterString, "");
                    output = output.Replace(delimiterString + Environment.NewLine, "");
    
                    // Console.Write(output);
                    break;
                }
    
            } while (lastChr > 0);
    
            return output;
        }
    

    【讨论】:

    • 这是我能找到的唯一有效的答案。无法相信内置功能无法做到这一点。谢谢!
    【解决方案2】:

    是否有任何方法可以检测正在运行的进程是否已完成加载我的命令并等待新输入?和 cmd 一样吗?

    即使是 cmd.exe 也不知道进程是否已经完成了你的命令。它确实知道进程正在等待输入,但那是因为它负责提供从中获取输入的用户交互。该进程,即使在等待输入时,也可以随时写入更多输出。

    在为控制台进程重定向 I/O 时,您必须像用户一样检测是否需要提供输入:观察输出以获取提示。

    不可能提供具体建议,因为您没有发布任何代码,更不用说可靠地重现问题的a good, minimal, complete code example。但一般来说,你应该能够循环,从输出中读取行,如果检测到提示,然后执行一些代码来提供适当的响应。

    例如:

    string line;
    while ((line = process.StandardOutput.ReadLine()) != null)
    {
        Console.WriteLine(line);
        if (line.EndsWith("Enter next command: "))
        {
            process.StandardInput.WriteLine("next command");
        }
    }
    

    【讨论】:

    • 感谢您的回答!问题是提示的最后一个字符是新行,这可能只是下一个输出的新行。所以没有真正的“特殊字符”或字符串可以帮助我检测提示。有任何想法吗?这有点烦人,因为没有真正合适的方法来做到这一点。
    • 上面的代码只是一个例子,实际上假定提示的最后一个字符是换行符(即上面的循环甚至不会看到提示,直到行终止)。您可以使用其他StreamReader 方法,例如Read() 来检索所有可用的字符输出,而不是等待换行符。无论哪种方式,必须有某种独特的文本可识别为提示,否则程序甚至人类用户如何识别是时候提供更多输入?如果你能提供一个具体的例子,可以提供一个更具体的答案。
    • 感谢您的帮助。如果我有一个很好的例子,我会更新
    • 好的,我已经检查过了。没有特殊字符串,新行只有10个。我阅读了 StandardOutput 和 StandardError。这让我发疯了。
    猜你喜欢
    • 1970-01-01
    • 2023-03-25
    • 2013-08-09
    • 1970-01-01
    • 1970-01-01
    • 2016-06-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多