Redirected batch file process output not running

蓝咒 提交于 2019-12-25 04:47:14

问题


I'm attempting to redirect output from a batch file execution to the main window of our console application.

I'm calling the method to run the process like this:

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

The method being called is as follows:

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"));
}

To try to figure out what is happening I've added extra calls to WriteLine.
"<<<got to here" gets written to the console then it just hangs and nothing further happens.

Suspect my mistake is something very trivial as my experience with this technology is limited.

What am I doing wrong?


回答1:


Since you want the child's output in the existing console, you don't need any redirection. Just set UseShellExecute to false and don't set CreateNoWindow.

This code works for me:

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");
        }
    }
}

I took out the redirection and associated logic, and the line that set CreateNoWindow. I also added aPath to the command line so that it would work for UNC paths (paths with no drive letter) since they can't be set as the working directory.




回答2:


Well, you're using ReadToEnd() - that's going to block until the process exits, basically.

This is an exceptionally bad idea when you're redirecting both Standard Output and Error - when the I/O buffer gets full, both of the applications are going to freeze.

Instead, you might want to use asynchronous I/O to read the output (and write it to console as needed - you'll need to make sure the Error and Output don't mess each other up, though). Or just redirect either one of those rather than both.

The easiest way to handle this is by using ErrorDataReceived and OutputDataReceived events:

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

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

aProcess.WaitForExit();

Apart from actually working, this also means that the output is printed out as it comes, rather than when the process exits.




回答3:


I amended the first option after if(aFiletype == "bat") and the bat files are running ok.

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"));
}


来源:https://stackoverflow.com/questions/30914435/redirected-batch-file-process-output-not-running

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!