【问题标题】:Redirected batch file process output not running重定向的批处理文件进程输出未运行
【发布时间】:2015-06-18 11:44:14
【问题描述】:

我正在尝试将批处理文件执行的输出重定向到控制台应用程序的主窗口。

我正在调用该方法来运行这样的过程:

this.runProcess("\\bar\foo\blah\", "myBatch1.bat", "bat");

被调用的方法如下:

public void runProcess(string aPath,string aName,string aFiletype)
{

  Console.WriteLine();
  Console.WriteLine();
  Console.WriteLine("Started: {0}",DateTime.Now.ToString("dd-MMM hh:mm:ss"));
  Console.WriteLine("Will try run this file {0} {1}",aPath,aName);
  Console.WriteLine("File type {0}",aFiletype);

  string stInfoFileName;
  string stInfoArgs;

  if(aFiletype == "bat")
  {
    stInfoFileName = @"cmd.exe";
    stInfoArgs = "//c " + aName;
  }
  else
  { //vbs
    stInfoFileName = @"cscript";
    stInfoArgs = "//B " + aName;
  }

  this.aProcess.StartInfo.FileName = stInfoFileName;
  this.aProcess.StartInfo.Arguments =  stInfoArgs;
  this.aProcess.StartInfo.WorkingDirectory = @aPath;
  this.aProcess.StartInfo.CreateNoWindow = true;
  this.aProcess.StartInfo.UseShellExecute = false;
  this.aProcess.StartInfo.RedirectStandardError = true;
  this.aProcess.StartInfo.RedirectStandardOutput = true;

  this.aProcess.Start();
  Console.WriteLine("<<<got to here");

  Console.WriteLine(this.aProcess.StandardOutput.ReadToEnd());
  Console.WriteLine(this.aProcess.StandardError.ReadToEnd());

  this.aProcess.WaitForExit(); //<-- Optional if you want program running until your script exit
  this.aProcess.Close();

  Console.WriteLine("Finished: {0}",DateTime.Now.ToString("dd-MMM hh:mm:ss"));
}

为了弄清楚发生了什么,我添加了对 WriteLine 的额外调用。
"&lt;&lt;&lt;got to here" 被写入控制台,然后它就挂起,没有进一步的事情发生。

怀疑我的错误是非常微不足道的,因为我对这项技术的经验有限。

我做错了什么?

【问题讨论】:

  • 为什么字符串中有双斜杠?这可能是cmd /c 不起作用的原因,因为您实际上发送的是命令处理器不接受的cmd //c
  • 另外,如果你想让子进程的输出到控制台,你为什么要打开重定向?如果重定向关闭,则输出应转到控制台而不需要任何额外的代码。
  • @HarryJohnston 好的 - 不确定双斜线出现在哪里,我将修改为 "/c ""/B "。就输出而言,我认为它默认被定向到批处理文件的子应用程序窗口,所以要将其定向到不同的位置重定向需要打开吗? (......但我第一次使用这些方法时感觉在黑暗中)。还有 Harry - 我目前正在使用的代码中此线程中的最后一篇文章......
  • 如果父进程有控制台,则子进程默认使用相同的控制台——换句话说,不应该有子窗口,前提是UseShellExecute设置为false。 (您也不需要设置CreateNoWindow。)
  • - 批处理文件通过单独的客户端应用程序将文件发送到 ftp。我试图通过注释掉你提到的行来简化它,它抛出了一个错误。我已将以下代码更新为我的工作版本。标记为//&lt;&lt;HJ 的两行一旦被注释掉就会导致错误。如果您想为我简化并测试一个工作版本,我会非常有兴趣使用它..

标签: c# batch-file process console-application


【解决方案1】:

好吧,你正在使用ReadToEnd() - 这基本上会一直阻塞,直到进程退出。

当您同时重定向标准输出和错误时,这是​​一个非常糟糕的主意 - 当 I/O 缓冲区已满时,两个应用程序都将冻结。

相反,您可能希望使用异步 I/O 来读取输出(并根据需要将其写入控制台 - 不过,您需要确保错误和输出不会相互混淆)。或者只是重定向其中一个而不是两者。

处理此问题的最简单方法是使用ErrorDataReceivedOutputDataReceived 事件:

aProcess.ErrorDataReceived += (s, e) => Console.WriteLine(e.Data);
aProcess.OutputDataReceived += (s, e) => Console.WriteLine(e.Data);

aProcess.BeginOutputReadLine();
aProcess.BeginErrorReadLine();

aProcess.WaitForExit();

除了实际工作之外,这还意味着输出在它到来时被打印出来,而不是在进程退出时。

【讨论】:

  • 感谢您的帮助:一定的改进。它现在将“Microsoft 2009..all rights reserved”消息打印到主控制台,但没有其他 ftp 消息(bat 文件正在处理的内容)被重定向,并且 ftp 文件没有被传输。
  • @whytheq 如果您只是在cmd 中运行脚本,它真的可以工作吗?
  • 它在cmd 中运行良好,但我刚刚发现了问题:我将在单独的帖子中详细说明。
  • 我正在从控制台应用程序运行几个进程,一些批处理和一些 vbs - 我只需要运行你给我的代码一次 - 我问的原因是我遇到了 InvalidOperationException this.aProcess.BeginOutputReadLine(); 行详细信息包括“已在流上启动异步读取操作”
  • 是的,只有一次。只要进程运行,它就会持续。
【解决方案2】:

由于您希望在现有控制台中输出孩子的输出,因此您不需要任何重定向。只需将UseShellExecute 设置为false,不要设置CreateNoWindow

此代码适用于我:

using System;
using System.Diagnostics;

namespace ConsoleApplication1
{
    class Program
    {
        Process aProcess = new Process();

        public void runProcess(string aPath, string aName, string aFiletype)
        {
            Console.WriteLine();
            Console.WriteLine();
            Console.WriteLine("Started: {0}", DateTime.Now.ToString("dd-MMM hh:mm:ss"));
            Console.WriteLine("Will try run this file {0} {1}", aPath, aName);
            Console.WriteLine("File type {0}", aFiletype);

            string stInfoFileName;
            string stInfoArgs;

            if (aFiletype == "bat")
            {
                stInfoFileName = "cmd.exe";
                stInfoArgs = "/c " + aPath + aName;
            }
            else
            { //vbs
                stInfoFileName = "cscript";
                stInfoArgs = "/B " + aPath + aName;
            }

            this.aProcess.StartInfo.FileName = stInfoFileName;
            this.aProcess.StartInfo.Arguments = stInfoArgs;
            this.aProcess.StartInfo.WorkingDirectory = aPath;
            this.aProcess.StartInfo.UseShellExecute = false;

            this.aProcess.Start();

            Console.WriteLine("<<<got to here");

            this.aProcess.WaitForExit(); //<-- Optional if you want program running until your script exit
            this.aProcess.Close();

            Console.WriteLine("Finished: {0}", DateTime.Now.ToString("dd-MMM hh:mm:ss"));
        }

        static void Main(string[] args)
        {
            new Program().runProcess("c:\\working\\", "test.bat", "bat");
            Console.WriteLine("Exiting");
        }
    }
}

我取出了重定向和相关逻辑,以及设置CreateNoWindow 的行。我还在命令行中添加了aPath,以便它适用于 UNC 路径(没有驱动器号的路径),因为它们不能设置为工作目录。

【讨论】:

  • 谢谢哈利。我们现在有一个功能齐全的死星。我所做的唯一修改是将这一行 stInfoArgs = "/c " + aPath + aName; 更改为 stInfoArgs = String.Format("/c \"{0}{1}\"", @aPath, @aName);,因为我在批处理文件的 UNC 路径中有空格。
【解决方案3】:

我修改了if(aFiletype == "bat") 之后的第一个选项,bat 文件运行正常。

public void runProcess(string aPath,string aName,string aFiletype)
{
  aProcess = new Process();

  Console.WriteLine();
  Console.WriteLine();
  Console.WriteLine("Started: {0}",DateTime.Now.ToString("dd-MMM hh:mm:ss"));
  Console.WriteLine("Will try run this file {0} {1}",aPath,aName);
  Console.WriteLine("File type {0}",aFiletype);

  string stInfoFileName;
  string stInfoArgs;

  if(aFiletype == "bat")
  {
    stInfoFileName = (@aPath + @aName);
    stInfoArgs = string.Empty;
  }
  else
  { //vbs
    stInfoFileName = @"cscript";
    stInfoArgs = "//B " + aName;
  }

  this.aProcess.StartInfo.FileName = stInfoFileName;
  this.aProcess.StartInfo.Arguments =  stInfoArgs;

  this.aProcess.StartInfo.WorkingDirectory = @aPath;

  //new 18 june 2015//////
  if(aFiletype == "bat")
  {
    this.aProcess.StartInfo.CreateNoWindow = true;
    this.aProcess.StartInfo.UseShellExecute = false;
    this.aProcess.StartInfo.RedirectStandardError = true;     //<< HJ
    this.aProcess.StartInfo.RedirectStandardOutput = true;    //<< HJ
  }
  ////////////////////////

  this.aProcess.StartInfo.WindowStyle = ProcessWindowStyle.Normal; //.Hidden
  this.aProcess.Start();

  aProcessName = this.aProcess.ProcessName;
  if(aFiletype == "bat")
  {
    this.aProcess.ErrorDataReceived += (s,e) => Console.WriteLine(e.Data);
    this.aProcess.OutputDataReceived += (s,e) => Console.WriteLine(e.Data);
    this.aProcess.BeginOutputReadLine();
    this.aProcess.BeginErrorReadLine();
  }

  this.aProcess.WaitForExit();
  this.aProcess.Dispose();

Console.WriteLine("Process {0} closed: {1}", this.aProcessName, DateTime.Now.ToString("dd-MMM hh:mm:ss"));
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2010-09-12
    • 1970-01-01
    • 1970-01-01
    • 2023-04-07
    • 2012-05-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多