public static string StartCmd(string commandLine)
{
ProcessStartInfo startInfo = new ProcessStartInfo("/bin/bash") {
UseShellExecute = false,
RedirectStandardInput = true,
RedirectStandardOutput = true
};
Process process = new Process {
StartInfo = startInfo
};
process.Start();
string code = commandLine;
process.StandardInput.WriteLine(code);
process.StandardInput.WriteLine("exit");
process.StandardInput.Flush();
string line = process.StandardOutput.ReadLine();
while(line != null) {
UnityEngine.Debug.LogError("line:" + line);
line = process.StandardOutput.ReadLine();
}
line += process.StandardOutput.ReadToEnd();
process.WaitForExit();
UnityEngine.Debug.LogError("return:" + line);
return string.IsNullOrEmpty(line) ? "" : line;
}
when I call this funciton by commandLine-“svn info 'my project'”, this funciton will return NULL. How can I get the expected output?
Related
I'm running .NET Core app on the linux docker container
When I call the command from the linux terminal it works well:
./darknet detector test -out result.json < data/file-list.txt
But when I start the process from the .NET Core I see error. Process runner method:
public static string RunCommand(string command, string args)
{
var process = new Process()
{
StartInfo = new ProcessStartInfo
{
FileName = command,
Arguments = args,
RedirectStandardOutput = true,
RedirectStandardError = true,
UseShellExecute = false,
CreateNoWindow = true
}
};
process.Start();
process.WaitForExit();
string output = process.StandardOutput.ReadToEnd();
string error = process.StandardError.ReadToEnd();
return #$"{output}{Environment.NewLine}-------------------------------{Environment.NewLine}{error}";
}
Calling code:
string args = #$"detector test -out result.json < data/file-list.txt";
string output = ProcessRunner.RunCommand("./darknet", args);
Here is the part of the output:
Cannot load image "<"
STB Reason: can't fopen
How to fix it?
You can write the process's standard input once you set the RedirectStandartInput to true while starting your process. Here is an example how to write :
var process = new Process()
{
StartInfo = new ProcessStartInfo
{
FileName = "./ConsoleApp1.exe",
RedirectStandardOutput = true,
RedirectStandardError = true,
RedirectStandardInput = true, // here you need
UseShellExecute = false,
CreateNoWindow = true,
}
};
process.Start();
using var file = File.OpenRead("./1.txt");
using var reader = new StreamReader(file);
while (true)
{
var line = await reader.ReadLineAsync();
if (string.IsNullOrWhiteSpace(line)) break; // you can use some other stoping decision
await process.StandardInput.WriteLineAsync(line);
}
I am trying to run a batch file using C#
The batch file for the test purposes contains
msg * Test
It works if I run it manually.
Then I use the following code to run this .bat file
filePath = full path to batch file
var startInfo = new ProcessStartInfo
{
Arguments = "/C \"" + filePath + "\"",
FileName = "cmd.exe",
UseShellExecute = true
};
Process p = Process.Start(startInfo);
and it does not work ->
cannot find msg
What I am doing wrong?
P.S. the batch file should not be changed.
Try this way:
batchfile:
set "msg=%SystemRoot%\System32\msg.exe"
if not exist "%msg%" set "msg=%SystemRoot%\Sysnative\msg.exe"
"%msg%" * Hello
code:
string sFile = <full path to batch file>;
Process.Start("cmd.exe", "/c " + sFile);
Probably need some authorization, you may try the following code:
static void ExecuteCommand(string command)
{
int exitCode;
ProcessStartInfo processInfo;
Process process;
processInfo = new ProcessStartInfo("cmd.exe", "/c " + command);
processInfo.CreateNoWindow = true;
processInfo.Domain = "domain"; // Your own domain
processInfo.UserName = "userName"; // Your own user name
System.Security.SecureString s = new System.Security.SecureString();
s.AppendChar('p'); // Your own password
s.AppendChar('a');
s.AppendChar('s');
s.AppendChar('s');
s.AppendChar('w');
s.AppendChar('o');
s.AppendChar('r');
s.AppendChar('d');
processInfo.Password = s;
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(#"C:\displayMsg.bat");
}
You may check your domain in Control Panel >> User Account >> Manage User Accounts
Source of reference: source
The problem is the location of the file (msg.exe) in the different OS versions (32bit/64bit)
I suppose it helps How can I execute msg.exe by C# in windows?
Edited:
It works fine -
class Program
{
static void Main(string[] args)
{
int ExitCode;
try
{
var returnedMsgPath = string.Empty;
if (LocateMsgExe(out returnedMsgPath))
{
var startInfo = new ProcessStartInfo()
{
FileName = returnedMsgPath,
Arguments = #"* /v Hello",
UseShellExecute = false,
CreateNoWindow = true,
RedirectStandardError = true,
RedirectStandardOutput = true
};
var p = Process.Start(startInfo);
p.WaitForExit();
// *** Read the streams ***
string output = p.StandardOutput.ReadToEnd();
string error = p.StandardError.ReadToEnd();
ExitCode = p.ExitCode;
MessageBox.Show("output >>" + (String.IsNullOrEmpty(output) ? "(none)" : output));
MessageBox.Show("error>>" + (String.IsNullOrEmpty(error) ? "(none)" : error));
MessageBox.Show("ExitCode: " + ExitCode.ToString(), "ExecuteCommand");
p.Close();
}
else
{
MessageBox.Show("Not found");
}
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}
public static bool LocateMsgExe(out string returnedMsgPath)
{
returnedMsgPath = null;
string[] msgPaths = new string[] { Environment.ExpandEnvironmentVariables(#"%windir%\system32\msg.exe"),
Environment.ExpandEnvironmentVariables(#"%windir%\sysnative\msg.exe") };
foreach (string msgPath in msgPaths)
{
if (File.Exists(msgPath))
{
returnedMsgPath = msgPath;
return true;
}
}
return false;
}
}
Running SqlCmd utility using C# this way :
// Calls the sqlcmd
ProcessStartInfo info = new ProcessStartInfo(
"sqlcmd",
#" -S VDSS218 -i D:\Ravi\Blank_Database_Creation_script.sql");
info.UseShellExecute = false;
info.CreateNoWindow = true;
info.WindowStyle = ProcessWindowStyle.Hidden;
info.RedirectStandardOutput = true;
Process proc = new Process();
proc.StartInfo = info;
proc.Start();
Now, If any error occurred in script while running from C# then how can fetch that SQL Exception in C#.
First, let's declare a class for executioning result:
public sealed class ExecutionSqlCmdResult {
public ExecutionSqlCmdResult(string stdOut, string stdErr, int exitCode)
: base() {
Out = string.IsNullOrWhiteSpace(stdOut) ? "" : stdOut;
Error = string.IsNullOrWhiteSpace(stdErr) ? "" : stdErr;
ExitCode = exitCode;
}
public string Out {
get;
}
public string Error {
get;
}
public int ExitCode {
get;
}
}
Then we can put
public static ExecutionSqlCmdResult ExecuteSqlCmd(string command) {
ProcessStartInfo sqlCmdInfo = new ProcessStartInfo() {
UseShellExecute = false,
CreateNoWindow = true,
WindowStyle = ProcessWindowStyle.Hidden,
RedirectStandardError = true,
RedirectStandardOutput = true,
Arguments = command,
FileName = "sqlcmd",
StandardErrorEncoding = Encoding.UTF8,
StandardOutputEncoding = Encoding.UTF8,
};
using (Process sqlCmdProcess = new Process()) {
sqlCmdProcess.StartInfo = sqlCmdInfo;
sqlCmdProcess.Start();
StringBuilder sbOut = new StringBuilder();
StringBuilder sbErr = new StringBuilder();
sqlCmdProcess.OutputDataReceived += (sender, e) => {
if (e.Data != null)
sbOut.Append(e.Data);
};
sqlCmdProcess.ErrorDataReceived += (sender, e) => {
if (e.Data != null)
sbErr.Append(e.Data);
};
sqlCmdProcess.BeginErrorReadLine();
sqlCmdProcess.BeginOutputReadLine();
sqlCmdProcess.WaitForExit();
return new ExecutionSqlCmdResult(sbOut.ToString(), sbErr.ToString(), sqlCmdProcess.ExitCode);
}
}
Usage
var result = ExecuteSqlCmd(#" -S VDSS218 -i D:\Ravi\Blank_Database_Creation_script.sql");
//TODO: inspect result.Out, result.Error and result.ExitCode
Listen to the event: ErrorDataReceived
proc.ErrorDataReceived += new DataReceivedEventHandler(method);
See full example on MSDN:
https://learn.microsoft.com/en-us/dotnet/api/system.diagnostics.process.errordatareceived?view=netframework-4.7.2
I wanna redirect cmd.exe output somewhere, below code works when the command is a line:
Process p = new Process()
{
StartInfo = new ProcessStartInfo("cmd")
{
UseShellExecute = false,
RedirectStandardInput = true,
RedirectStandardOutput = true,
CreateNoWindow = true,
Arguments = String.Format("/c \"{0}\"", command),
}
};
p.OutputDataReceived += (s, e) => Messagebox.Show(e.Data);
p.Start();
p.BeginOutputReadLine();
p.WaitForExit();
But how about a series commands like WriteLine():
p.StandardInput.WriteLine("cd...");
p.StandardInput.WriteLine("dir");
how to get output in this situation?
To achieve such behavior you should use /k switch to run cmd.exe in interactive mode.
The problem is to separate inputs from different commands.
To do this you could change the standard prompt using prompt command:
prompt --Prompt_C2BCE8F8E2C24403A71CA4B7F7521F5B_F659E9F3F8574A72BE92206596C423D5
So now it is pretty easy to determine the end of command output.
Here is the complete code:
public static IEnumerable<string> RunCommands(params string[] commands) {
var process = new Process {
StartInfo = new ProcessStartInfo("cmd") {
UseShellExecute = false,
RedirectStandardInput = true,
RedirectStandardOutput = true,
CreateNoWindow = true,
Arguments = "/k",
}
};
process.Start();
const string prompt = "--Prompt_C2BCE8F8E2C24403A71CA4B7F7521F5B_F659E9F3F8574A72BE92206596C423D5 ";
// replacing standard prompt in order to determine end of command output
process.StandardInput.WriteLine("prompt " + prompt);
process.StandardInput.Flush();
process.StandardOutput.ReadLine();
process.StandardOutput.ReadLine();
var result = new List<string>();
try {
var commandResult = new StringBuilder();
foreach (var command in commands) {
process.StandardInput.WriteLine(command);
process.StandardInput.WriteLine();
process.StandardInput.Flush();
process.StandardOutput.ReadLine();
while (true) {
var line = process.StandardOutput.ReadLine();
if (line == prompt) // end of command output
break;
commandResult.AppendLine(line);
}
result.Add(commandResult.ToString());
commandResult.Clear();
}
} finally {
process.Kill();
}
return result;
}
It works well but it looks like one big hack.
I'd recommend you to use process per command instead.
How can running CMD from c# without to see the cmd windows?
In ProcessStartInfo there's a parameter called CreateNoWindow
public static string ExecuteCommand(string command) {
ProcessStartInfo procStartInfo = new ProcessStartInfo("cmd", "/c " + command)
{
RedirectStandardError = true,
RedirectStandardOutput = true,
UseShellExecute = false,
CreateNoWindow = true
};
using (Process proc = new Process())
{
proc.StartInfo = procStartInfo;
proc.Start();
string output = proc.StandardOutput.ReadToEnd();
if (string.IsNullOrEmpty(output))
output = proc.StandardError.ReadToEnd();
return output;
}
}