我想从我的Mono/运行一个外部命令行程序。网络应用程序。 例如,我想运行mencoder。有没有可能:
获得命令行shell输出,并将其写在我的文本框? 获取数值以显示随着时间流逝的进度条?
我想从我的Mono/运行一个外部命令行程序。网络应用程序。 例如,我想运行mencoder。有没有可能:
获得命令行shell输出,并将其写在我的文本框? 获取数值以显示随着时间流逝的进度条?
当前回答
在调用Process.StandardOutput.ReadLine和Process.StandardOutput.ReadToEnd时,我遇到了臭名昭著的死锁问题。
我的目标/用例很简单。启动一个进程并重定向它的输出,这样我就可以捕获输出并通过. net Core的ILogger<T>将其记录到控制台,并将重定向的输出附加到文件日志中。
下面是我使用内置异步事件处理程序的解决方案。OutputDataReceived和Process.ErrorDataReceived。
var p = new Process
{
StartInfo = new ProcessStartInfo(
command.FileName, command.Arguments
)
{
RedirectStandardOutput = true,
RedirectStandardError = true,
UseShellExecute = false,
}
};
// Asynchronously pushes StdOut and StdErr lines to a thread safe FIFO queue
var logQueue = new ConcurrentQueue<string>();
p.OutputDataReceived += (sender, args) => logQueue.Enqueue(args.Data);
p.ErrorDataReceived += (sender, args) => logQueue.Enqueue(args.Data);
// Start the process and begin streaming StdOut/StdErr
p.Start();
p.BeginOutputReadLine();
p.BeginErrorReadLine();
// Loop until the process has exited or the CancellationToken is triggered
do
{
var lines = new List<string>();
while (logQueue.TryDequeue(out var log))
{
lines.Add(log);
_logger.LogInformation(log)
}
File.AppendAllLines(_logFilePath, lines);
// Asynchronously sleep for some time
try
{
Task.Delay(5000, stoppingToken).Wait(stoppingToken);
}
catch(OperationCanceledException) {}
} while (!p.HasExited && !stoppingToken.IsCancellationRequested);
其他回答
当你适当地创建Process对象集StartInfo时:
var proc = new Process
{
StartInfo = new ProcessStartInfo
{
FileName = "program.exe",
Arguments = "command line arguments to your executable",
UseShellExecute = false,
RedirectStandardOutput = true,
CreateNoWindow = true
}
};
然后开始这个过程并从中读取:
proc.Start();
while (!proc.StandardOutput.EndOfStream)
{
string line = proc.StandardOutput.ReadLine();
// do something with line
}
可以使用int.Parse()或int.TryParse()将字符串转换为数值。如果读取的字符串中有无效的数字字符,则可能必须先进行一些字符串操作。
在win和linux中为我工作的解决方案如下
// GET api/values
[HttpGet("cifrado/{xml}")]
public ActionResult<IEnumerable<string>> Cifrado(String xml)
{
String nombreXML = DateTime.Now.ToString("ddMMyyyyhhmmss").ToString();
String archivo = "/app/files/"+nombreXML + ".XML";
String comando = " --armor --recipient bibankingprd@bi.com.gt --encrypt " + archivo;
try{
System.IO.File.WriteAllText(archivo, xml);
//String comando = "C:\\GnuPG\\bin\\gpg.exe --recipient licorera@local.com --armor --encrypt C:\\Users\\Administrador\\Documents\\pruebas\\nuevo.xml ";
ProcessStartInfo startInfo = new ProcessStartInfo() {FileName = "/usr/bin/gpg", Arguments = comando };
Process proc = new Process() { StartInfo = startInfo, };
proc.StartInfo.RedirectStandardOutput = true;
proc.StartInfo.RedirectStandardError = true;
proc.Start();
proc.WaitForExit();
Console.WriteLine(proc.StandardOutput.ReadToEnd());
return new string[] { "Archivo encriptado", archivo + " - "+ comando};
}catch (Exception exception){
return new string[] { archivo, "exception: "+exception.ToString() + " - "+ comando };
}
}
可以获得一个进程的命令行shell输出,如下所示:http://www.c-sharpcorner.com/UploadFile/edwinlima/SystemDiagnosticProcess12052005035444AM/SystemDiagnosticProcess.aspx 这取决于mencoder。如果它在命令行输出这个状态,那么是:)
好吧,对于任何想要读取错误和输出,但得到任何解决方案死锁的人,在其他答案中提供(像我),这里是一个解决方案,我在阅读MSDN对StandardOutput属性的解释后构建的。
答案是基于T30的代码:
static void runCommand()
{
//* Create your Process
Process process = new Process();
process.StartInfo.FileName = "cmd.exe";
process.StartInfo.Arguments = "/c DIR";
process.StartInfo.UseShellExecute = false;
process.StartInfo.RedirectStandardOutput = true;
process.StartInfo.RedirectStandardError = true;
//* Set ONLY ONE handler here.
process.ErrorDataReceived += new DataReceivedEventHandler(ErrorOutputHandler);
//* Start process
process.Start();
//* Read one element asynchronously
process.BeginErrorReadLine();
//* Read the other one synchronously
string output = process.StandardOutput.ReadToEnd();
Console.WriteLine(output);
process.WaitForExit();
}
static void ErrorOutputHandler(object sendingProcess, DataReceivedEventArgs outLine)
{
//* Do your stuff with the output (write to console/log/StringBuilder)
Console.WriteLine(outLine.Data);
}
您可以同步或异步地处理输出。
1. 同步的例子
static void runCommand()
{
Process process = new Process();
process.StartInfo.FileName = "cmd.exe";
process.StartInfo.Arguments = "/c DIR"; // Note the /c command (*)
process.StartInfo.UseShellExecute = false;
process.StartInfo.RedirectStandardOutput = true;
process.StartInfo.RedirectStandardError = true;
process.Start();
//* Read the output (or the error)
string output = process.StandardOutput.ReadToEnd();
Console.WriteLine(output);
string err = process.StandardError.ReadToEnd();
Console.WriteLine(err);
process.WaitForExit();
}
注意,最好同时处理输出和错误:它们必须分别处理。
(*)对于某些命令(这里是StartInfo.Arguments),你必须添加/c指令,否则进程会在WaitForExit()中冻结。
2. 异步的例子
static void runCommand()
{
//* Create your Process
Process process = new Process();
process.StartInfo.FileName = "cmd.exe";
process.StartInfo.Arguments = "/c DIR";
process.StartInfo.UseShellExecute = false;
process.StartInfo.RedirectStandardOutput = true;
process.StartInfo.RedirectStandardError = true;
//* Set your output and error (asynchronous) handlers
process.OutputDataReceived += new DataReceivedEventHandler(OutputHandler);
process.ErrorDataReceived += new DataReceivedEventHandler(OutputHandler);
//* Start process and handlers
process.Start();
process.BeginOutputReadLine();
process.BeginErrorReadLine();
process.WaitForExit();
}
static void OutputHandler(object sendingProcess, DataReceivedEventArgs outLine)
{
//* Do your stuff with the output (write to console/log/StringBuilder)
Console.WriteLine(outLine.Data);
}
如果你不需要对输出做复杂的操作,你可以绕过OutputHandler方法,只需直接内联添加处理程序:
//* Set your output and error (asynchronous) handlers
process.OutputDataReceived += (s, e) => Console.WriteLine(e.Data);
process.ErrorDataReceived += (s, e) => Console.WriteLine(e.Data);