1

Could you please explain why the shell redirection doesn't work with System.Diagnostics.Process class? I am trying to redirect the output streams to file with the following snippet:

Process p = new Process();
p.StartInfo = new ProcessStartInfo();
p.StartInfo.FileName = "java.exe";
p.StartInfo.Arguments = @"> c:\Temp\test.log 2>&1";
p.StartInfo.UseShellExecute = true;
p.Start();

The similar code works without problems with Python. Reading the output streams programmatically doesn't seem a preferable solution in my case because there will be a bunch of processes launched by my application.

Mher
  • 77
  • 1
  • 3

3 Answers3

3

It is because there is no shell to process those arguments. When you type your command line to shell, it gets parsed, program arguments separated from the shell "special" modifiers, and only then launched. In C# this doesn't happen because there is no "cmd.exe" or "bash" process to do it.

To redirect input in C# you should set p.StartInfo.RedirectStandardOutput to true, then use p.StandardOutput to read data and then write it to a file.

Alternatively, you can run a "cmd.exe" with parameters required to execute the process and redirect its output. Although not cross-platform, this should be easier to do than to write efficient data stream passing implementation yourself.

Rotsor
  • 13,655
  • 6
  • 43
  • 57
  • But I set ProcessStartInfo.UseShellExecute to true in order to launch the process using shell. What is the meaning of ProcessStartInfo.UseShellExecute in that case? Thanks! – Mher Jun 16 '10 at 08:55
  • @Mher http://msdn.microsoft.com/en-us/library/system.diagnostics.processstartinfo.useshellexecute.aspx It's roughly equivalent to double-clicking on a registered file, or using `start foo.doc` at the command line - it uses the shell's handler for the given file type. – Pete Kirkham Jun 16 '10 at 09:00
  • 'UseShellExecute = false' roughly doesn't allow the process to interact with file system when in a WindowsService environment loged as a domain user – Davi Fiamenghi Oct 03 '12 at 14:20
3

You cannot do the redirection because there is no shell directly involved. You could run a cmd.exe session, but the proper way to do it is using the RedirectStandardOutput/Error properties. There is no problem when having many processes. This is a class I use for this.

    class HandleExecutable {
        private DataReceivedEventHandler outputHandler;

        public DataReceivedEventHandler OutputHandler
        {
            set { outputHandler = value; }
        }
        private DataReceivedEventHandler errorHandler;

        public DataReceivedEventHandler ErrorHandler
        {
            set { errorHandler = value; }
        }

        public void callExecutable(string executable, string args)
        {
            string commandLine = executable;
            string args = args;
            ProcessStartInfo psi = new ProcessStartInfo(commandLine);
            psi.UseShellExecute = false;
            psi.LoadUserProfile = false;
            psi.RedirectStandardOutput = true;
            psi.RedirectStandardError = true;
            psi.WindowStyle = ProcessWindowStyle.Minimized;
            psi.CreateNoWindow = true;
            psi.Arguments = args;
            p = new Process();
            p.StartInfo = psi;
            try
            {
                p.Start();
                p.BeginOutputReadLine();
                p.BeginErrorReadLine();
                if (outputHandler != null) p.OutputDataReceived += outputHandler;
                if (errorHandler != null) p.ErrorDataReceived += errorHandler;
                p.WaitForExit();
                p.Close();
                p.Dispose();
            }
            catch (Exception ex)
            {
                log.Error(ex.Message);
            }
        }
    }

    //On another class
    void p_ErrorDataReceived(object sender, DataReceivedEventArgs e)
    {
        //HANDLE STDERR
        if (e.Data != null && !e.Data.Equals(""))
        {
             if (!e.Data.Contains("Something")) {
             }
        }
    }

    void p_OutputDataReceived(object sender, DataReceivedEventArgs e)
    {
        //HANDLE STDOUT
        if (e.Data != null && !e.Data.Equals(""))
        {
        }
    }

    HandleExecutable he = new HandleExecutable();
    he.OutputHandler = p_OutputDataReceived;
    he.ErrorHandler = p_ErrorDataReceived;
    he.callExecutable(@"C:\java.exe","-cp foo ClassName");
Vinko Vrsalovic
  • 330,807
  • 53
  • 334
  • 373
  • Ideally you should set the event-handlers before starting to read. If you don't, you will risk missing the first bit of output. For an example see http://stackoverflow.com/questions/415620/redirect-console-output-to-textbox-in-separate-program-c-sharp – Yahoo Serious Oct 01 '12 at 08:30
0

If you want to redirect the output streams you have to configure it. Set the Redirect... properties and read the streams. You can find an example here.

Regards

DHN
  • 4,807
  • 3
  • 31
  • 45