重定向的批处理文件过程输出不是 运行
Redirected batch file process output not running
我正在尝试将批处理文件执行的输出重定向到控制台应用程序的主要 window。
我正在调用方法 运行 过程如下:
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
的额外调用。
"<<<got to here"
被写入控制台,然后它就挂起,没有进一步发生。
怀疑我的错误是非常微不足道的,因为我对这项技术的经验有限。
我做错了什么?
好吧,您正在使用 ReadToEnd()
- 基本上,它将阻塞直到进程退出。
当您同时重定向标准输出和错误时,这是一个非常糟糕的主意 - 当 I/O 缓冲区变满时,两个应用程序都将冻结。
相反,您可能希望使用异步 I/O 来读取输出(并根据需要将其写入控制台 - 您需要确保错误和输出不会相互混淆,尽管)。或者只重定向其中之一而不是两者。
处理此问题的最简单方法是使用 ErrorDataReceived
和 OutputDataReceived
事件:
aProcess.ErrorDataReceived += (s, e) => Console.WriteLine(e.Data);
aProcess.OutputDataReceived += (s, e) => Console.WriteLine(e.Data);
aProcess.BeginOutputReadLine();
aProcess.BeginErrorReadLine();
aProcess.WaitForExit();
除了实际工作之外,这还意味着输出会在出现时打印出来,而不是在进程退出时打印出来。
我在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"));
}
由于您希望在现有控制台中输出子项,因此不需要任何重定向。只需将 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 路径(没有驱动器号的路径),因为它们不能被设置为工作目录。
我正在尝试将批处理文件执行的输出重定向到控制台应用程序的主要 window。
我正在调用方法 运行 过程如下:
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
的额外调用。
"<<<got to here"
被写入控制台,然后它就挂起,没有进一步发生。
怀疑我的错误是非常微不足道的,因为我对这项技术的经验有限。
我做错了什么?
好吧,您正在使用 ReadToEnd()
- 基本上,它将阻塞直到进程退出。
当您同时重定向标准输出和错误时,这是一个非常糟糕的主意 - 当 I/O 缓冲区变满时,两个应用程序都将冻结。
相反,您可能希望使用异步 I/O 来读取输出(并根据需要将其写入控制台 - 您需要确保错误和输出不会相互混淆,尽管)。或者只重定向其中之一而不是两者。
处理此问题的最简单方法是使用 ErrorDataReceived
和 OutputDataReceived
事件:
aProcess.ErrorDataReceived += (s, e) => Console.WriteLine(e.Data);
aProcess.OutputDataReceived += (s, e) => Console.WriteLine(e.Data);
aProcess.BeginOutputReadLine();
aProcess.BeginErrorReadLine();
aProcess.WaitForExit();
除了实际工作之外,这还意味着输出会在出现时打印出来,而不是在进程退出时打印出来。
我在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"));
}
由于您希望在现有控制台中输出子项,因此不需要任何重定向。只需将 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 路径(没有驱动器号的路径),因为它们不能被设置为工作目录。