Piping Shell Output with C#

.NET DevelopmentThe C# Process class helps interface with the Windows shell, enabling developers to run DOS commands or other programs.  It offers a variety of configuration options, enabling both direct input and output to shell programs, and asynchronous execution.  In this tutorial, we will go over a pair of scriplets that simplify execution of shell commands from within C#.

The RunCmd scriplets come in the two flavors below.  In its simplest configuration, the function can be called with only the command and startup folder, resulting in the function executing the command and displaying the output to the console window.  Alternatively, an output filename can be added to pipe the output directly to a text file.

 
public static void RunCmd(string cmd,string working_dir){ RunCmd(cmd,working_dir,""); }
public static void RunCmd(string cmd,string working_dir,string pipeout){
  Process proc = new Process();
  ProcessStartInfo psi = new ProcessStartInfo();
  psi.WorkingDirectory = working_dir;
  psi.FileName = "cmd.exe";
  psi.Arguments = "/c " + cmd;
  psi.WindowStyle = ProcessWindowStyle.Hidden;
  psi.RedirectStandardOutput = true;
  psi.UseShellExecute = false;
  proc.StartInfo = psi;
  if(String.IsNullOrEmpty(pipeout)){
    proc.OutputDataReceived += new DataReceivedEventHandler((s, e) => {
      if(!String.IsNullOrEmpty(e.Data)) Console.WriteLine(e.Data);
    });
  }
  else{
    proc.OutputDataReceived += new DataReceivedEventHandler((s, e) => {
      if(!String.IsNullOrEmpty(e.Data)) File.AppendAllText(pipeout,e.Data+"\r\n");
    });
  }
  proc.Start();
  proc.BeginOutputReadLine();
  proc.WaitForExit();
}

The initial body of the function is relatively straightforward.  RunCmd uses the Windows cmd.exe executable to run arbitrary DOS commands in the shell.  This can be used with almost any DOS command, from a simple “dir”, all the way to Perl and Python script execution from within the context of the Windows shell.

The two key options that enable piping the output, either for debugging or for further utilization, are “RedirectStandardOutput” and “UseShellExecute”.  RedirectStandardOutput must be set to true, so that the OutputDataReceived event will be called when the program sends back data.  UseShellExecute, on the other hand, must be set to false, so that the OutputDataReceived event will be latched directly to the cmd.exe executable; otherwise the event will be bypassed regardless of the RedirectStandardOutput flag.

Although the OutputDataReceived events could be bound with an external event handler, the anonymous function is simpler for the illustrated example.  It’s important to verify that the Data passed from the output pipe is tested to be non-null, otherwise further operations may result in a program crash.

These two scriplets are a useful addition to any C# developer toolbox.  By utilizing the RunCmd methods, the nuances of shell command execution can be simplified for future use.

Written by Andrew Palczewski

About the Author
Andrew Palczewski is CEO of apHarmony, a Chicago software development company. He holds a Master's degree in Computer Engineering from the University of Illinois at Urbana-Champaign and has over ten years' experience in managing development of software projects.
Google+

RSS Twitter LinkedIn Facebook Email

One thought on “Piping Shell Output with C#”

  1. Could you please provide an example of how to use this code? For example, To sort a directory listing based on the time the files were last modified, the output of a directory listing is piped to the SORT filter which sorts on the 39th character of each line:
    DIR c:\data\docs | SORT /+39, this is how DOS/Windows Shell pipe works. How can I do the same with the above code? Thanks.

Leave a Reply

Your email address will not be published. Required fields are marked *