Piping in a File on the Command-Line Using System.Diagnostics.Process

Piping in a file on the command-line using System.Diagnostics.Process

Both Mark and Luke gave me the right direction to go. I couldn't use either answer because I had to do this so that it could run with Mono in Linux. So I ended up writing to the StandardInput as suggested. Here is the code that works:

public static bool ExecuteSvnCommandWithFileInput( string command, string arguments, string filePath, out string result, out string errors )
{
bool retval = false;
string output = string.Empty;
string errorLines = string.Empty;
Process svnCommand = null;
var psi = new ProcessStartInfo( command );

psi.RedirectStandardInput = true;
psi.RedirectStandardOutput = true;
psi.RedirectStandardError = true;
psi.WindowStyle = ProcessWindowStyle.Hidden;
psi.UseShellExecute = false;
psi.CreateNoWindow = true;

try
{
Process.Start( psi );
psi.Arguments = arguments;
svnCommand = Process.Start( psi );

var file = new FileInfo(filePath);
StreamReader reader = file.OpenText();
string fileContents = reader.ReadToEnd();
reader.Close();

StreamWriter myWriter = svnCommand.StandardInput;
StreamReader myOutput = svnCommand.StandardOutput;
StreamReader myErrors = svnCommand.StandardError;

myWriter.AutoFlush = true;
myWriter.Write(fileContents);
myWriter.Close();

output = myOutput.ReadToEnd();
errorLines = myErrors.ReadToEnd();

// Check for errors
if ( errorLines.Trim().Length == 0 )
{
retval = true;
}
}
catch ( Exception ex )
{
string msg = ex.Message;
errorLines += Environment.NewLine + msg;
}
finally
{
if (svnCommand != null)
{
svnCommand.Close();
}
}

result = output;
errors = errorLines;

return retval;
}

System.Diagnostics.Process pipe (vertical bar) not accepted as argument

Thanks to Lee his comments, the problem has been resolved. Just invoke cmd.exe and pass it the full command:

var myProcess = new Process();
var p = new ProcessStartInfo("cmd.exe");
var sArgs = "/C ffmpeg.exe -i emp.mp3 -f wav - | neroAacEnc -ignorelength -q 0.5 -if - -of emp.mp4";
p.CreateNoWindow = false;
p.RedirectStandardOutput = false;
p.UseShellExecute = false;
p.Arguments = sArgs;
myProcess.StartInfo = p;
myProcess.Start();
myProcess.WaitForExit();

Piping output into to a windows executable started by [Diagnostics.Process]::Start?

Ansgar Wiechers' helpful answer contains an effective solution and sensible security warnings.

Using a System.Diagnostics.Process instance with .RedirectStandardInput = $true, and use of .StandardInput to provide standard input after the process has started, gives you more flexibility, yet in your case the only modification that was needed was to pass your command line as an argument (2nd parameter), via option -c, to program cmd.exe (1st parameter).

  • [Diagnostics.Process]::Start()'s first parameter is only the executable name / path, not a full command line.

  • It is the 2nd parameter that accepts a string containing the arguments to pass to the executable.

  • Since you're using shell features, namely connecting multiple commands with a pipeline, you must use cmd.exe as the executable, and pass your pipeline as an argument to cmd.exe's /c option.

    • You could use powershell.exe too, but in this simple case it is sufficient - and faster - to use cmd.exe.

Here's a simplified example:

$meProcessID = ([Diagnostics.Process]::Start(
# Program to launch
'cmd',
# Arguments to pass
'/c echo 42 | powershell -nop -c "''stdin input: '' + $Input" & pause'
).Id

The above demonstrates that stdin input 42 is seen by the powershell process as such ($Input); it opens a new console window that shows the following:

stdin input: 42
Press any key to continue . . .

How to get the output of a System.Diagnostics.Process?

What you need to do is capture the Standard Output stream:

p.StartInfo.RedirectStandardOutput = true;
p.StartInfo.UseShellExecute = false;
// instead of p.WaitForExit(), do
string q = "";
while ( ! p.HasExited ) {
q += p.StandardOutput.ReadToEnd();
}

You may also need to do something similar with StandardError. You can then do what you wish with q.

It is a bit finicky, as I discovered in one of my questions

As Jon Skeet has pointed out, it is not smart performance-wise to use string concatenation like this; you should instead use a StringBuilder:

p.StartInfo.RedirectStandardOutput = true;
p.StartInfo.UseShellExecute = false;
// instead of p.WaitForExit(), do
StringBuilder q = new StringBuilder();
while ( ! p.HasExited ) {
q.Append(p.StandardOutput.ReadToEnd());
}
string r = q.ToString();

How To: Execute command line in C#, get STD OUT results

// Start the child process.
Process p = new Process();
// Redirect the output stream of the child process.
p.StartInfo.UseShellExecute = false;
p.StartInfo.RedirectStandardOutput = true;
p.StartInfo.FileName = "YOURBATCHFILE.bat";
p.Start();
// Do not wait for the child process to exit before
// reading to the end of its redirected stream.
// p.WaitForExit();
// Read the output stream first and then wait.
string output = p.StandardOutput.ReadToEnd();
p.WaitForExit();

Code is from MSDN.

Redirect a process's output to both a file and the console

Could use something like that

using System;
using System.Diagnostics;

namespace InteractWithConsoleApp
{
class Program
{
static void Main(string[] args)
{
ProcessStartInfo cmdStartInfo = new ProcessStartInfo();
cmdStartInfo.FileName = @"C:\Windows\System32\cmd.exe";
cmdStartInfo.RedirectStandardOutput = true;
cmdStartInfo.RedirectStandardError = true;
cmdStartInfo.RedirectStandardInput = true;
cmdStartInfo.UseShellExecute = false;
cmdStartInfo.CreateNoWindow = true;

Process cmdProcess = new Process();
cmdProcess.StartInfo = cmdStartInfo;
cmdProcess.ErrorDataReceived += cmd_Error;
cmdProcess.OutputDataReceived += cmd_DataReceived;
cmdProcess.EnableRaisingEvents = true;
cmdProcess.Start();
cmdProcess.BeginOutputReadLine();
cmdProcess.BeginErrorReadLine();

cmdProcess.StandardInput.WriteLine("ping google.com.ua"); //Execute ping google.com.ua
cmdProcess.StandardInput.WriteLine("exit"); //Execute exit.

cmdProcess.WaitForExit();
}

static void cmd_DataReceived(object sender, DataReceivedEventArgs e)
{
Console.WriteLine("Output from other process");
Console.WriteLine(e.Data);
}

static void cmd_Error(object sender, DataReceivedEventArgs e)
{
Console.WriteLine("Error from other process");
Console.WriteLine(e.Data);
}
}
}


Related Topics



Leave a reply



Submit