Aylien Sentiment Analysis using Console application - c#

I'm facing a problem. I am using Aylien API for sentiment analysis. When i run this code, i will get a value of neutral 0.99823.
static void Main(string[] args)
{
Client client = new Client("ID", "Key");
string filename = "tweet.txt"; // Declare the file name
string inputString = System.IO.File.ReadAllText(filename); // Read all text in File to String.
Sentiment sentiment = client.Sentiment(text: inputString);
Console.WriteLine("The Tweets are : " + sentiment.Polarity + " " + sentiment.PolarityConfidence);
Console.WriteLine(sentiment.Subjectivity + " " + sentiment.SubjectivityConfidence+"\n");
Console.WriteLine("Press ENTER to close...");
Console.ReadLine();
}
However when i run my second code to invoke the method from another console application, it always display positive 1. Do anyone know why?
var proc = Process.Start(#"C:\\ConsoleApplication1");
proc.WaitForExit();
var exitCode = proc.ExitCode;

You're getting the exit code from the process, which generally indicates success/failure, 0 generally means the process ended successfully, anything else generally means something went wrong, although the creator of your app could be returning anything they want.
If you want to get the output from the actual application you should read the standard output from process by doing the following:
var proc = new Process();
proc.StartInfo.FileName = #"C:\\ConsoleApplication1";
proc.StartInfo.UseShellExecute = false;
proc.StartInfo.RedirectStandardOutput = true;
proc.OutputDataReceived += Proc_OutputDataReceived;
proc.Start();
proc.BeginOutputReadLine();
proc.WaitForExit();
private static void Proc_OutputDataReceived(object sender, DataReceivedEventArgs e)
{
Console.WriteLine(e.Data);
}

Related

How to get execution command window in c#

I execute a command from my C# App.
It runs fine but sometimes I get errors.
My problem is that I cannot see which is the error or any other text in the command window.
It is just blank.
Is there any way I can make the text show up in the execution time same as it is appeared here?
Here is my code:
var processInfo = new ProcessStartInfo("cmd.exe", "/c " + command);
//processInfo.CreateNoWindow = true;
processInfo.UseShellExecute = false;
processInfo.RedirectStandardError = true;
processInfo.RedirectStandardOutput = true;
processInfo.WorkingDirectory = workingFolder;
var process = Process.Start(processInfo);
process.OutputDataReceived += (object sender, DataReceivedEventArgs e) =>
Console.WriteLine("output>>" + e.Data);//MessageBox.Show(e.Data);
process.BeginOutputReadLine();
process.ErrorDataReceived += (object sender, DataReceivedEventArgs e) =>
Console.WriteLine("error>>" + e.Data);//MessageBox.Show(e.Data);
process.BeginErrorReadLine();
process.WaitForExit();
Console.WriteLine("ExitCode: {0}", process.ExitCode);
process.Close();
There is nothing wrong with your code, the problem is that you run your program in the wrong path.
Follow these steps to find the path of your app:
Then, in the cmd.exe go to the path with bunch of cd commands.
Here is the code:
var command = "echo hello world"; // < ------ example
var processInfo = new ProcessStartInfo("cmd.exe", "/c " + command);
//processInfo.CreateNoWindow = true;
processInfo.UseShellExecute = false;
processInfo.RedirectStandardError = true;
processInfo.RedirectStandardOutput = true;
The output:
output>>hello world
output>>
error>>
ExitCode: 0
Press any key to continue . . .
Also, you can run your app with Ctrl + F5
I know these are so obvious but it's worth to mention them.
Update
You should specify a command, maybe you don't set any command or your command has ~no output~
Update2
I change the code, when the user send args to myapp.exe, it directs it to run.
static void Main(string[] args)
{
var command = string.Join("", args);
var processInfo = new ProcessStartInfo("cmd.exe", "/c " + command);
...
Output:
C:\Users\Mahan\Source\Repos\ConsoleApp11\ConsoleApp11\bin\Debug>myapp.exe echo hello
output>>hello world
output>>
error>>
ExitCode: 0
In your first screenshot there is Select in the title bar of the cmd window.
Are you aware of the fact that the program gets paused then?
The Select happens if you click in the window and can be continued by pressing Enter (if I remember correctly).
If you use Console.WriteLine() and the cmd window is not paused, you should see what ever you have written.
I am not an expert on that but I think you can write this code in a try-catch block and make the exception message be shown on screen using Console.WriteLine() command.

Why does redirected standard output appear after process has finished?

I am working with Visual Studio 2015 and .NET framework 4.7.2. I have set up a simple test program that executes an external program in C#. The program is a Python script that simply prints some string to stdout every 0.5 seconds. I want to read the stdout of this sub process in my C# application.
The program basically works, but I get the output of the Python script only shortly before the sub process exits. What do I need to change in order to get a more responsive behavior, i.e. getting the output every 0.5 second as soon as the Python script writes it to stdout?
Here's my C# code:
public class Program {
private Process process;
public static void Main(string[] args) {
new Program().init();
}
private void init() {
startPythonProcess();
process.WaitForExit();
Console.ReadLine();
}
private void startPythonProcess() {
if(process==null) {
try {
Console.WriteLine("Starting Python process ...");
string filepath = Path.GetDirectoryName(Assembly.GetExecutingAssembly().CodeBase).Substring(6);
process = new Process();
ProcessStartInfo startInfo = new ProcessStartInfo();
startInfo.CreateNoWindow = false;
startInfo.UseShellExecute = false;
startInfo.WorkingDirectory = filepath;
startInfo.FileName = "python.exe";
//startInfo.WindowStyle = ProcessWindowStyle.Normal;
startInfo.RedirectStandardInput = false;
startInfo.RedirectStandardOutput = true;
startInfo.RedirectStandardError = true;
startInfo.Arguments = string.Format("{0}", Path.Combine(filepath, "test.py"));
process.StartInfo = startInfo;
process.OutputDataReceived += OutputDataReceivedEventHandler;
process.ErrorDataReceived += ErrorDataReceivedEventHandler;
process.Start();
process.BeginOutputReadLine();
process.BeginErrorReadLine();
} catch(Exception ex) {
Console.WriteLine("Could not start Python process: " + ex.Message);
}
}
}
public void OutputDataReceivedEventHandler(object sender, DataReceivedEventArgs args) {
Console.WriteLine("[PYTHON] INFO: {0}", args.Data);
}
public void ErrorDataReceivedEventHandler(object sender, DataReceivedEventArgs args) {
Console.WriteLine("[PYTHON] ERROR: {0}", args.Data);
}
}
Here's my Python script:
import time
import sys
import logging
logging.basicConfig(level=logging.ERROR)
if __name__ == '__main__':
count = 0
while True:
print('PYTHON: {}'.format(count))
time.sleep(0.5)
count+=1
if count>=25:
break
UPDATE: I uploaded the mini project here.
The print function takes a flush argument which controls whether buffered output is flushed.
The default value of flush is False, meaning flushing is controlled by whatever file print is writing to (for example, sys.stdout).
Set flush to True to force immediate printing.
print('PYTHON: {}'.format(count), flush=True)

how to execute batch file in c# [duplicate]

I'm trying to execute a batch file in C#, but I'm not getting any luck doing it.
I've found multiple examples on the Internet doing it, but it is not working for me.
public void ExecuteCommand(string command)
{
int ExitCode;
ProcessStartInfo ProcessInfo;
Process Process;
ProcessInfo = new ProcessStartInfo("cmd.exe", "/c " + command);
ProcessInfo.CreateNoWindow = true;
ProcessInfo.UseShellExecute = false;
Process = Process.Start(ProcessInfo);
Process.WaitForExit();
ExitCode = Process.ExitCode;
Process.Close();
MessageBox.Show("ExitCode: " + ExitCode.ToString(), "ExecuteCommand");
}
The command string contains the name of the batch file (stored in system32) and some files it should manipulate. (Example: txtmanipulator file1.txt file2.txt file3.txt). When I execute the batch file manually, it works correctly.
When executing the code, it gives me an **ExitCode: 1** (Catch all for general errors)
What am I doing wrong?
This should work. You could try to dump out the contents of the output and error streams in order to find out what's happening:
static void ExecuteCommand(string command)
{
int exitCode;
ProcessStartInfo processInfo;
Process process;
processInfo = new ProcessStartInfo("cmd.exe", "/c " + command);
processInfo.CreateNoWindow = true;
processInfo.UseShellExecute = false;
// *** Redirect the output ***
processInfo.RedirectStandardError = true;
processInfo.RedirectStandardOutput = true;
process = Process.Start(processInfo);
process.WaitForExit();
// *** Read the streams ***
// Warning: This approach can lead to deadlocks, see Edit #2
string output = process.StandardOutput.ReadToEnd();
string error = process.StandardError.ReadToEnd();
exitCode = process.ExitCode;
Console.WriteLine("output>>" + (String.IsNullOrEmpty(output) ? "(none)" : output));
Console.WriteLine("error>>" + (String.IsNullOrEmpty(error) ? "(none)" : error));
Console.WriteLine("ExitCode: " + exitCode.ToString(), "ExecuteCommand");
process.Close();
}
static void Main()
{
ExecuteCommand("echo testing");
}
* EDIT *
Given the extra information in your comment below, I was able to recreate the problem. There seems to be some security setting that results in this behaviour (haven't investigated that in detail).
This does work if the batch file is not located in C:\Windows\System32. Try moving it to some other location, e.g. the location of your executable. Note that keeping custom batch files or executables in the Windows directory is bad practice anyway.
* EDIT 2 *
It turns out that if the streams are read synchronously, a deadlock can occur, either by reading synchronously before WaitForExit or by reading both stderr and stdout synchronously one after the other.
This should not happen if using the asynchronous read methods instead, as in the following example:
static void ExecuteCommand(string command)
{
var processInfo = new ProcessStartInfo("cmd.exe", "/c " + command);
processInfo.CreateNoWindow = true;
processInfo.UseShellExecute = false;
processInfo.RedirectStandardError = true;
processInfo.RedirectStandardOutput = true;
var process = Process.Start(processInfo);
process.OutputDataReceived += (object sender, DataReceivedEventArgs e) =>
Console.WriteLine("output>>" + e.Data);
process.BeginOutputReadLine();
process.ErrorDataReceived += (object sender, DataReceivedEventArgs e) =>
Console.WriteLine("error>>" + e.Data);
process.BeginErrorReadLine();
process.WaitForExit();
Console.WriteLine("ExitCode: {0}", process.ExitCode);
process.Close();
}
System.Diagnostics.Process.Start("c:\\batchfilename.bat");
this simple line will execute the batch file.
After some great help from steinar this is what worked for me:
public void ExecuteCommand(string command)
{
int ExitCode;
ProcessStartInfo ProcessInfo;
Process process;
ProcessInfo = new ProcessStartInfo(Application.StartupPath + "\\txtmanipulator\\txtmanipulator.bat", command);
ProcessInfo.CreateNoWindow = true;
ProcessInfo.UseShellExecute = false;
ProcessInfo.WorkingDirectory = Application.StartupPath + "\\txtmanipulator";
// *** Redirect the output ***
ProcessInfo.RedirectStandardError = true;
ProcessInfo.RedirectStandardOutput = true;
process = Process.Start(ProcessInfo);
process.WaitForExit();
// *** Read the streams ***
string output = process.StandardOutput.ReadToEnd();
string error = process.StandardError.ReadToEnd();
ExitCode = process.ExitCode;
MessageBox.Show("output>>" + (String.IsNullOrEmpty(output) ? "(none)" : output));
MessageBox.Show("error>>" + (String.IsNullOrEmpty(error) ? "(none)" : error));
MessageBox.Show("ExitCode: " + ExitCode.ToString(), "ExecuteCommand");
process.Close();
}
It works fine. I tested it like this:
String command = #"C:\Doit.bat";
ProcessInfo = new ProcessStartInfo("cmd.exe", "/c " + command);
// ProcessInfo.CreateNoWindow = true;
I commented out turning off the window so I could SEE it run.
Here is sample c# code that are sending 2 parameters to a bat/cmd file for answer this question.
Comment: how can I pass parameters and read a result of command execution?
/by #Janatbek Sharsheyev
Option 1 : Without hiding the console window, passing arguments and without getting the outputs
This is an edit from this answer /by #Brian Rasmussen
using System;
using System.Diagnostics;
namespace ConsoleApplication
{
class Program
{
static void Main(string[] args)
{
System.Diagnostics.Process.Start(#"c:\batchfilename.bat", "\"1st\" \"2nd\"");
}
}
}
Option 2 : Hiding the console window, passing arguments and taking outputs
using System;
using System.Diagnostics;
namespace ConsoleApplication
{
class Program
{
static void Main(string[] args)
{
var process = new Process();
var startinfo = new ProcessStartInfo(#"c:\batchfilename.bat", "\"1st_arg\" \"2nd_arg\" \"3rd_arg\"");
startinfo.RedirectStandardOutput = true;
startinfo.UseShellExecute = false;
process.StartInfo = startinfo;
process.OutputDataReceived += (sender, argsx) => Console.WriteLine(argsx.Data); // do whatever processing you need to do in this handler
process.Start();
process.BeginOutputReadLine();
process.WaitForExit();
}
}
}
// C# decode bat file and run passing arguments: // edit 01/2022
using System;
using System.IO;
using System.Text;
using System.Diagnostics;
namespace ConsoleApplication
{
class Program
{
static void Main(string[] args)
{
String encodedString = #"QGVjaG8gb2ZmIAoKc2V0ICJ4PUZvbGRlciIKeGNvcHkgL3kgL3YgL2UgLlw
iJXglIlwqIFxcMTAuMC4wLjIwMFxkXAoKZm9yICUleSBpbiAoMjAyLDIwMy
wyMDQsMjA1KWRvICgKICAgICBuZXQgdXNlIFxcMTAuMC4wLiUlfnlcZSAiJ
X4xIiAvdXNlcjoiJX4yIgogICAgIGVjaG9cQ29weWluZyBmaWxlcyB0byBc
XDEwLjAuMC4lJX55XGVcCiAgICAgeGNvcHkgL3kgL3YgL2UgLlwiJXglIlw
qIFxcMTAuMC4wLiUlfnlcZVwKICAgICk=";
File.WriteAllBytes(#"z:\batchfilename.bat", Convert.FromBase64String(encodedString));
System.Diagnostics.Process.Start(#"z:\batchfilename.bat", "\"PassWord1\" \"User1\"");
}
}
}
/* bat file decoded:
#echo off
set "x=Folder"
xcopy /y /v /e .\"%x%"\* \\10.0.0.200\d\
for %%y in (202,203,204,205)do (
net use \\10.0.0.%%~y\e "%~1" /user:"%~2"
echo\Copying files to \\10.0.0.%%~y\e\
xcopy /y /v /e .\"%x%"\* \\10.0.0.%%~y\e\
)
Execute bat:
#"z:\batchfilename.bat", "\"PassWord1\" \"User1\""
Bat argument:
Argument %1 == PassWord1 Argument %2 == User1
*/
1. Create your bat and test it as much as possible
2. Convert the code to base64
3. Defines a variable in your code with the base64 strings
4. Decode at runtime to a pre-defined and proper location for execution
5. Call the bat execution on the path where it was decodes
6. If necessary, pass your arguments
Below code worked fine for me
using System.Diagnostics;
public void ExecuteBatFile()
{
Process proc = null;
string _batDir = string.Format(#"C:\");
proc = new Process();
proc.StartInfo.WorkingDirectory = _batDir;
proc.StartInfo.FileName = "myfile.bat";
proc.StartInfo.CreateNoWindow = false;
proc.Start();
proc.WaitForExit();
ExitCode = proc.ExitCode;
proc.Close();
MessageBox.Show("Bat file executed...");
}
using System.Diagnostics;
private void ExecuteBatFile()
{
Process proc = null;
try
{
string targetDir = string.Format(#"D:\mydir"); //this is where mybatch.bat lies
proc = new Process();
proc.StartInfo.WorkingDirectory = targetDir;
proc.StartInfo.FileName = "lorenzo.bat";
proc.StartInfo.Arguments = string.Format("10"); //this is argument
proc.StartInfo.CreateNoWindow = false;
proc.StartInfo.WindowStyle = ProcessWindowStyle.Hidden; //this is for hiding the cmd window...so execution will happen in back ground.
proc.Start();
proc.WaitForExit();
}
catch (Exception ex)
{
Console.WriteLine("Exception Occurred :{0},{1}", ex.Message, ex.StackTrace.ToString());
}
}
Have you tried starting it as an administrator? Start Visual Studio as an administrator if you use it, because working with .bat files requires those privileges.
With previously proposed solutions, I have struggled to get multiple npm commands executed in a loop and get all outputs on the console window.
It finally started to work after I have combined everything from the previous comments, but rearranged the code execution flow.
What I have noticed is that event subscribing was done too late (after the process has already started) and therefore some outputs were not captured.
The code below now does the following:
Subscribes to the events, before the process has started,
therefore ensuring that no output is missed.
Begins reading from outputs as soon as the process is started.
The code has been tested against the deadlocks, although it is synchronous (one process execution at the time) so I cannot guarantee what would happen if this was run in parallel.
static void RunCommand(string command, string workingDirectory)
{
Process process = new Process
{
StartInfo = new ProcessStartInfo("cmd.exe", $"/c {command}")
{
WorkingDirectory = workingDirectory,
CreateNoWindow = true,
UseShellExecute = false,
RedirectStandardError = true,
RedirectStandardOutput = true
}
};
process.OutputDataReceived += (object sender, DataReceivedEventArgs e) => Console.WriteLine("output :: " + e.Data);
process.ErrorDataReceived += (object sender, DataReceivedEventArgs e) => Console.WriteLine("error :: " + e.Data);
process.Start();
process.BeginOutputReadLine();
process.BeginErrorReadLine();
process.WaitForExit();
Console.WriteLine("ExitCode: {0}", process.ExitCode);
process.Close();
}
I wanted something that was more directly usable without organization-specific hard-coded string values in it. I offer the following as a directly reusable chunk of code. The minor downside is needing to determine and pass the working folder when making the call.
public static void ExecuteCommand(string command, string workingFolder)
{
int ExitCode;
ProcessStartInfo ProcessInfo;
Process process;
ProcessInfo = new ProcessStartInfo("cmd.exe", "/c " + command);
ProcessInfo.CreateNoWindow = true;
ProcessInfo.UseShellExecute = false;
ProcessInfo.WorkingDirectory = workingFolder;
// *** Redirect the output ***
ProcessInfo.RedirectStandardError = true;
ProcessInfo.RedirectStandardOutput = true;
process = Process.Start(ProcessInfo);
process.WaitForExit();
// *** Read the streams ***
string output = process.StandardOutput.ReadToEnd();
string error = process.StandardError.ReadToEnd();
ExitCode = process.ExitCode;
MessageBox.Show("output>>" + (String.IsNullOrEmpty(output) ? "(none)" : output));
MessageBox.Show("error>>" + (String.IsNullOrEmpty(error) ? "(none)" : error));
MessageBox.Show("ExitCode: " + ExitCode.ToString(), "ExecuteCommand");
process.Close();
}
Called like this:
// This will get the current WORKING directory (i.e. \bin\Debug)
string workingDirectory = Environment.CurrentDirectory;
// This will get the current PROJECT directory
string projectDirectory = Directory.GetParent(workingDirectory).Parent.FullName;
string commandToExecute = Path.Combine(projectDirectory, "TestSetup", "WreckersTestSetupQA.bat");
string workingFolder = Path.GetDirectoryName(commandToExecute);
commandToExecute = QuotesAround(commandToExecute);
ExecuteCommand(commandToExecute, workingFolder);
In this example, from within Visual Studio 2017, as part of a test run, I want to run an environment reset batch file before executing some tests. (SpecFlow+xUnit). I got tired of extra steps for manually running the bat file separately, and wanted to just run the bat file as part of the C# test setup code. The environment reset batch file moves test case files back into the input folder, cleans up output folders, etc. to get to the proper test starting state for testing. The QuotesAround method simply puts quotes around the command line in case there are spaces in folder names ("Program Files", anyone?). All that's in it is this: private string QuotesAround(string input) {return "\"" + input + "\"";}
Hope some find this useful and save a few minutes if your scenario is similar to mine.
System.Diagnostics.Process.Start(BatchFileName, Parameters);
I know this will work for batch file and parameters, but no ideas how to get the results in C#.
Usually, the outputs are defined in the batch file.
Using CliWrap:
var result = await Cli.Wrap("foobar.bat").ExecuteBufferedAsync();
var exitCode = result.ExitCode;
var stdOut = result.StandardOutput;

How to compile Java from C#?

I'm trying to use the following C# code to compile Java using javac:
Process p = new Process();
p.StartInfo.FileName = "javac";
Directory.CreateDirectory(Application.StartupPath + #"/TempJava");
p.StartInfo.Arguments = "-d "Application.StartupPath + #"/TempJava" + files;
p.Start();
"files" represents a string variable containing the name(s) of the *.java files.
All in all, I want to create a new folder, and then take the Java files (from where ever they may be located) and compile it into a class file(s) in TempJava.
For some reason, the code doesn't work, no errors, no warnings, but when I run it and check TempJava, there's no files in it.
Just because your child process ends with a possible error, it doesn't mean your parent process must be aware of it.
Inspect the process' exit code and standard output stream, and especially the standard error stream. Your answer lies in there...
here i have 2 buttons run and compile here is some code to help.
private void comp_Click(object sender, EventArgs e)
{
string text = "javac " + label1.Text + file + "#pause" + "#stop";
text = text.Replace("#", System.Environment.NewLine);
File.WriteAllText(label1.Text + "Compile.bat", text);
Process proc = null;
try
{
proc = new Process();
proc.StartInfo.FileName = label1.Text + "Compile.bat";
proc.StartInfo.CreateNoWindow = false;
proc.Start();
proc.WaitForExit();
}
catch
{
}
}
private void runp_Click(object sender, EventArgs e)
{
string news = file.Remove(file.Length - 5);
string text = "java " + news + "#pause";
text = text.Replace("#", System.Environment.NewLine);
File.WriteAllText(label1.Text + "Run.bat", text);
Process proc = null;
try
{
proc = new Process();
proc.StartInfo.FileName = label1.Text + "Run.bat";
proc.StartInfo.WorkingDirectory = label1.Text.Remove(label1.Text.Length - 1);
proc.StartInfo.CreateNoWindow = true;
proc.Start();
proc.WaitForExit();
}
catch
{
}
}
all i really do is create a batch and run it using c#.

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

How do I execute a command-line program from C# and get back the STD OUT results? Specifically, I want to execute DIFF on two files that are programmatically selected and write the results to a text box.
// 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.
Here's a quick sample:
//Create process
System.Diagnostics.Process pProcess = new System.Diagnostics.Process();
//strCommand is path and file name of command to run
pProcess.StartInfo.FileName = strCommand;
//strCommandParameters are parameters to pass to program
pProcess.StartInfo.Arguments = strCommandParameters;
pProcess.StartInfo.UseShellExecute = false;
//Set output of program to be written to process output stream
pProcess.StartInfo.RedirectStandardOutput = true;
//Optional
pProcess.StartInfo.WorkingDirectory = strWorkingDirectory;
//Start the process
pProcess.Start();
//Get program output
string strOutput = pProcess.StandardOutput.ReadToEnd();
//Wait for process to finish
pProcess.WaitForExit();
There one other parameter I found useful, which I use to eliminate the process window
pProcess.StartInfo.CreateNoWindow = true;
this helps to hide the black console window from user completely, if that is what you desire.
// usage
const string ToolFileName = "example.exe";
string output = RunExternalExe(ToolFileName);
public string RunExternalExe(string filename, string arguments = null)
{
var process = new Process();
process.StartInfo.FileName = filename;
if (!string.IsNullOrEmpty(arguments))
{
process.StartInfo.Arguments = arguments;
}
process.StartInfo.CreateNoWindow = true;
process.StartInfo.WindowStyle = ProcessWindowStyle.Hidden;
process.StartInfo.UseShellExecute = false;
process.StartInfo.RedirectStandardError = true;
process.StartInfo.RedirectStandardOutput = true;
var stdOutput = new StringBuilder();
process.OutputDataReceived += (sender, args) => stdOutput.AppendLine(args.Data); // Use AppendLine rather than Append since args.Data is one line of output, not including the newline character.
string stdError = null;
try
{
process.Start();
process.BeginOutputReadLine();
stdError = process.StandardError.ReadToEnd();
process.WaitForExit();
}
catch (Exception e)
{
throw new Exception("OS error while executing " + Format(filename, arguments)+ ": " + e.Message, e);
}
if (process.ExitCode == 0)
{
return stdOutput.ToString();
}
else
{
var message = new StringBuilder();
if (!string.IsNullOrEmpty(stdError))
{
message.AppendLine(stdError);
}
if (stdOutput.Length != 0)
{
message.AppendLine("Std output:");
message.AppendLine(stdOutput.ToString());
}
throw new Exception(Format(filename, arguments) + " finished with exit code = " + process.ExitCode + ": " + message);
}
}
private string Format(string filename, string arguments)
{
return "'" + filename +
((string.IsNullOrEmpty(arguments)) ? string.Empty : " " + arguments) +
"'";
}
The accepted answer on this page has a weakness that is troublesome in rare situations. There are two file handles which programs write to by convention, stdout, and stderr.
If you just read a single file handle such as the answer from Ray, and the program you are starting writes enough output to stderr, it will fill up the output stderr buffer and block. Then your two processes are deadlocked. The buffer size may be 4K.
This is extremely rare on short-lived programs, but if you have a long running program which repeatedly outputs to stderr, it will happen eventually. This is tricky to debug and track down.
There are a couple good ways to deal with this.
One way is to execute cmd.exe instead of your program and use the /c argument to cmd.exe to invoke your program along with the "2>&1" argument to cmd.exe to tell it to merge stdout and stderr.
var p = new Process();
p.StartInfo.FileName = "cmd.exe";
p.StartInfo.Arguments = "/c mycmd.exe 2>&1";
Another way is to use a programming model which reads both handles at the same time.
var p = new Process();
p.StartInfo.FileName = "cmd.exe";
p.StartInfo.Arguments = #"/c dir \windows";
p.StartInfo.CreateNoWindow = true;
p.StartInfo.RedirectStandardError = true;
p.StartInfo.RedirectStandardOutput = true;
p.StartInfo.RedirectStandardInput = false;
p.OutputDataReceived += (a, b) => Console.WriteLine(b.Data);
p.ErrorDataReceived += (a, b) => Console.WriteLine(b.Data);
p.Start();
p.BeginErrorReadLine();
p.BeginOutputReadLine();
p.WaitForExit();
System.Diagnostics.ProcessStartInfo psi =
new System.Diagnostics.ProcessStartInfo(#"program_to_call.exe");
psi.RedirectStandardOutput = true;
psi.WindowStyle = System.Diagnostics.ProcessWindowStyle.Hidden;
psi.UseShellExecute = false;
System.Diagnostics.Process proc = System.Diagnostics.Process.Start(psi); ////
System.IO.StreamReader myOutput = proc.StandardOutput;
proc.WaitForExit(2000);
if (proc.HasExited)
{
string output = myOutput.ReadToEnd();
}
You will need to use ProcessStartInfo with RedirectStandardOutput enabled - then you can read the output stream. You might find it easier to use ">" to redirect the output to a file (via the OS), and then simply read the file.
[edit: like what Ray did: +1]
One-liner run command:
new Process() { StartInfo = new ProcessStartInfo("echo", "Hello, World") }.Start();
Read output of command in shortest amount of reable code:
var cliProcess = new Process() {
StartInfo = new ProcessStartInfo("echo", "Hello, World") {
UseShellExecute = false,
RedirectStandardOutput = true
}
};
cliProcess.Start();
string cliOut = cliProcess.StandardOutput.ReadToEnd();
cliProcess.WaitForExit();
cliProcess.Close();
In case you also need to execute some command in the cmd.exe, you can do the following:
// 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 = "cmd.exe";
p.StartInfo.Arguments = "/C vol";
p.Start();
// Read the output stream first and then wait.
string output = p.StandardOutput.ReadToEnd();
p.WaitForExit();
Console.WriteLine(output);
This returns just the output of the command itself:
You can also use StandardInput instead of StartInfo.Arguments:
// Start the child process.
Process p = new Process();
// Redirect the output stream of the child process.
p.StartInfo.UseShellExecute = false;
p.StartInfo.RedirectStandardInput = true;
p.StartInfo.RedirectStandardOutput = true;
p.StartInfo.FileName = "cmd.exe";
p.Start();
// Read the output stream first and then wait.
p.StandardInput.WriteLine("vol");
p.StandardInput.WriteLine("exit");
string output = p.StandardOutput.ReadToEnd();
p.WaitForExit();
Console.WriteLine(output);
The result looks like this:
Since the most answers here dont implement the using statemant for IDisposable and some other stuff wich I think could be nessecary I will add this answer.
For C# 8.0
// Start a process with the filename or path with filename e.g. "cmd". Please note the
//using statemant
using myProcess.StartInfo.FileName = "cmd";
// add the arguments - Note add "/c" if you want to carry out tge argument in cmd and
// terminate
myProcess.StartInfo.Arguments = "/c dir";
// Allows to raise events
myProcess.EnableRaisingEvents = true;
//hosted by the application itself to not open a black cmd window
myProcess.StartInfo.UseShellExecute = false;
myProcess.StartInfo.CreateNoWindow = true;
// Eventhander for data
myProcess.Exited += OnOutputDataRecived;
// Eventhandler for error
myProcess.ErrorDataReceived += OnErrorDataReceived;
// Eventhandler wich fires when exited
myProcess.Exited += OnExited;
// Starts the process
myProcess.Start();
//read the output before you wait for exit
myProcess.BeginOutputReadLine();
// wait for the finish - this will block (leave this out if you dont want to wait for
// it, so it runs without blocking)
process.WaitForExit();
// Handle the dataevent
private void OnOutputDataRecived(object sender, DataReceivedEventArgs e)
{
//do something with your data
Trace.WriteLine(e.Data);
}
//Handle the error
private void OnErrorDataReceived(object sender, DataReceivedEventArgs e)
{
Trace.WriteLine(e.Data);
//do something with your exception
throw new Exception();
}
// Handle Exited event and display process information.
private void OnExited(object sender, System.EventArgs e)
{
Trace.WriteLine("Process exited");
}
Here is small example:
using System;
using System.Diagnostics;
class Program
{
static void Main(string[] args)
{
var p = Process.Start(
new ProcessStartInfo("git", "branch --show-current")
{
CreateNoWindow = true,
UseShellExecute = false,
RedirectStandardError = true,
RedirectStandardOutput = true,
WorkingDirectory = Environment.CurrentDirectory
}
);
p.WaitForExit();
string branchName =p.StandardOutput.ReadToEnd().TrimEnd();
string errorInfoIfAny =p.StandardError.ReadToEnd().TrimEnd();
if (errorInfoIfAny.Length != 0)
{
Console.WriteLine($"error: {errorInfoIfAny}");
}
else {
Console.WriteLine($"branch: {branchName}");
}
}
}
I believe this is shortest form.
Please notice that most of command line tools easily confuse standard output and standard error, sometimes it makes sense just to clue those together into single string.
Also p.ExitCode might be sometimes useful.
Example above serves for purpose of writing command line utility like tools if you want to do it by yourself. Please note that for cli automation it's also possible to use Cake Frosten and Cake Git extension.
You can launch any command line program using the Process class, and set the StandardOutput property of the Process instance with a stream reader you create (either based on a string or a memory location). After the process completes, you can then do whatever diff you need to on that stream.
This might be useful for someone if your attempting to query the local ARP cache on a PC/Server.
List<string[]> results = new List<string[]>();
using (Process p = new Process())
{
p.StartInfo.CreateNoWindow = true;
p.StartInfo.RedirectStandardOutput = true;
p.StartInfo.UseShellExecute = false;
p.StartInfo.Arguments = "/c arp -a";
p.StartInfo.FileName = #"C:\Windows\System32\cmd.exe";
p.Start();
string line;
while ((line = p.StandardOutput.ReadLine()) != null)
{
if (line != "" && !line.Contains("Interface") && !line.Contains("Physical Address"))
{
var lineArr = line.Trim().Split(' ').Select(n => n).Where(n => !string.IsNullOrEmpty(n)).ToArray();
var arrResult = new string[]
{
lineArr[0],
lineArr[1],
lineArr[2]
};
results.Add(arrResult);
}
}
p.WaitForExit();
}
This may not be the best/easiest way, but may be an option:
When you execute from your code, add " > output.txt" and then read in the output.txt file.
There is a ProcessHelper Class in PublicDomain open source code which might interest you.
Julian's solution is tested working with some minor corrections. The following is an example that also used https://sourceforge.net/projects/bat-to-exe/ GenericConsole.cs and https://www.codeproject.com/Articles/19225/Bat-file-compiler program.txt for args part:
using System;
using System.Text; //StringBuilder
using System.Diagnostics;
using System.IO;
class Program
{
private static bool redirectStandardOutput = true;
private static string buildargument(string[] args)
{
StringBuilder arg = new StringBuilder();
for (int i = 0; i < args.Length; i++)
{
arg.Append("\"" + args[i] + "\" ");
}
return arg.ToString();
}
static void Main(string[] args)
{
Process prc = new Process();
prc.StartInfo = //new ProcessStartInfo("cmd.exe", String.Format("/c \"\"{0}\" {1}", Path.Combine(Environment.CurrentDirectory, "mapTargetIDToTargetNameA3.bat"), buildargument(args)));
//new ProcessStartInfo(Path.Combine(Environment.CurrentDirectory, "mapTargetIDToTargetNameA3.bat"), buildargument(args));
new ProcessStartInfo("mapTargetIDToTargetNameA3.bat");
prc.StartInfo.Arguments = buildargument(args);
prc.EnableRaisingEvents = true;
if (redirectStandardOutput == true)
{
prc.StartInfo.UseShellExecute = false;
}
else
{
prc.StartInfo.UseShellExecute = true;
}
prc.StartInfo.CreateNoWindow = true;
prc.OutputDataReceived += OnOutputDataRecived;
prc.ErrorDataReceived += OnErrorDataReceived;
//prc.Exited += OnExited;
prc.StartInfo.RedirectStandardOutput = redirectStandardOutput;
prc.StartInfo.RedirectStandardError = redirectStandardOutput;
try
{
prc.Start();
prc.BeginOutputReadLine();
prc.BeginErrorReadLine();
prc.WaitForExit();
}
catch (Exception e)
{
Console.WriteLine("OS error: " + e.Message);
}
prc.Close();
}
// Handle the dataevent
private static void OnOutputDataRecived(object sender, DataReceivedEventArgs e)
{
//do something with your data
Console.WriteLine(e.Data);
}
//Handle the error
private static void OnErrorDataReceived(object sender, DataReceivedEventArgs e)
{
Console.WriteLine(e.Data);
}
// Handle Exited event and display process information.
//private static void OnExited(object sender, System.EventArgs e)
//{
// var process = sender as Process;
// if (process != null)
// {
// Console.WriteLine("ExitCode: " + process.ExitCode);
// }
// else
// {
// Console.WriteLine("Process exited");
// }
//}
}
The code need to compile inside VS2007, using commandline csc.exe generated executable will not show console output correctly, or even crash with CLR20r3 error. Comment out the OnExited event process, the console output of the bat to exe will be more like the original bat console output.
Just for fun, here's my completed solution for getting PYTHON output - under a button click - with error reporting. Just add a button called "butPython" and a label called "llHello"...
private void butPython(object sender, EventArgs e)
{
llHello.Text = "Calling Python...";
this.Refresh();
Tuple<String,String> python = GoPython(#"C:\Users\BLAH\Desktop\Code\Python\BLAH.py");
llHello.Text = python.Item1; // Show result.
if (python.Item2.Length > 0) MessageBox.Show("Sorry, there was an error:" + Environment.NewLine + python.Item2);
}
public Tuple<String,String> GoPython(string pythonFile, string moreArgs = "")
{
ProcessStartInfo PSI = new ProcessStartInfo();
PSI.FileName = "py.exe";
PSI.Arguments = string.Format("\"{0}\" {1}", pythonFile, moreArgs);
PSI.CreateNoWindow = true;
PSI.UseShellExecute = false;
PSI.RedirectStandardError = true;
PSI.RedirectStandardOutput = true;
using (Process process = Process.Start(PSI))
using (StreamReader reader = process.StandardOutput)
{
string stderr = process.StandardError.ReadToEnd(); // Error(s)!!
string result = reader.ReadToEnd(); // What we want.
return new Tuple<String,String> (result,stderr);
}
}

Categories