I have an external app with a number of arguments I need to run programmatically. It's all working fine in a command prompt but when I try to launch the same arguments from a .Net app, it fails. I've now learned it's the use of '&&' that is making the mess at the moment that some of the arguments has.
To simplify my question, say I have something like this working in my command prompt:
"Notepad.exe C:\tmp\tmp.txt && Notepad.exe c:\tmp\tmp2.txt"
This works fine. My attempt to achieve the equivalent looks like this:
string app = "Notepad.exe";
string args = #"C:\tmp\tmp.txt && Notepad.exe c:\tmp\tmp2.txt";
using (Process process = new Process())
{
process.StartInfo = new ProcessStartInfo(app, args)
{
UseShellExecute = false,
CreateNoWindow = false,
};
process.Start();
process.WaitForExit();
}
But this obviously does not work. Is my only option to split the arguments by '&&' and run them one by one or is there a way to make this work?
Try this:
string args = #"C:\tmp\tmp.txt && Notepad.exe c:\tmp\tmp2.txt";
The reason is that \ starts an escape sequence, meaning the text you pass as arguments is really this:
C: mp mp.txt && Notepad.exe c: mp mp2.txt
\t is the escape sequence for a tab.
The only difference between my code and your is the # in front of the string. This tells the compiler to interpret the string literally. If you need to know more, the name for this is "verbatim string".
UPDATE:
You can use this code:
string app = "cmd";
string args = #"/c Notepad.exe C:\tmp\tmp.txt && Notepad.exe c:\tmp\tmp2.txt";
using (Process process = new Process())
{
process.StartInfo = new ProcessStartInfo(app, args)
{
UseShellExecute = false,
CreateNoWindow = true,
};
process.Start();
process.WaitForExit();
}
It will use cmd.exe to execute the compounded command. I changed CreateNoWindow to true to not show the command line window, but only the notepad windows.
Have a method:
private void RunAndWait(string app, params string[] args)
{
foreach (string arg in args)
{
Process proc = new Process
{
StartInfo = new ProcessStartInfo(app, arg)
{
UseShellExecute = false,
CreateNoWindow = true
}
};
proc.Start();
proc.WaitForExit();
}
}
And then the code very is simple:
string app = "Notepad.exe";
string args1 = #"C:\tmp\tmp.txt";
string args2 = #"C:\tmp\tmp2.txt";
RunAndWait(app, args1, args2);
And to generalize for more than two files (args):
string[] args = new string[] {#"C:\tmp\tmp.txt", #"C:\tmp\tmp2.txt", ...}
RunAndWait(app, args);
Related
I am writing a CLI app to hide some of the details of running commands in the shell/terminal.
With the code below I can execute a single command ssh, for example:
var result = RunCommand("ssh", "100.100.109.86");
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();
var output = process.StandardOutput.ReadToEnd();
var error = process.StandardError.ReadToEnd();
return string.IsNullOrEmpty(error) ? output : error;
}
My question is how can implement a loop so that I can output the result of the command to the user and enable them to execute another command (or more)?
For example, the response to the above ssh command might as the to ask them if they are sure they want to connect inviting them to respond with (yes/no/[fingerprint])
I'm trying to include opening Git Bash, pushing and pulling in my c# code. Whilst opening Git Bash with Process.Start() is not the problem, I cannot manage to write commands into Git Bash.
I've tried including commands in ProcessStartInfo.Arguments, as well as redirecting the standard Output. Both has not worked at all. Down below you can see the different code snippets I tried.
private void Output()
{
//Try 1
processStartInfo psi = new ProcessStartInfo();
psi.FileName = "C:\ProgramData\Microsoft\Windows\Start Menu\Programs\Git\Git Bash.lnk";
psi.UseShellExecute = false;
psi.RedirectStandardOutput = true;
psi.Argument = "git add *";
Process p = Process.Start(psi);
string strOutput = p.StandardOutput.ReadToEnd();
Console.WriteLine(strOutput);
//Try 2
ProcessStartInfo psi = new ProcessStartInfo(#"C:\ProgramData\Microsoft\Windows\Start Menu\Programs\Git\Git Bash.lnk");
Process.Start(psi);
psi.Arguments = "git add *";
Process.Start(psi);
//Try 3
var escapedArgs = cmd.Replace("\"", "\\\"");
var process = new Process()
{
StartInfo = new ProcessStartInfo
{
FileName = #"C:\ProgramData\Microsoft\Windows\Start Menu\Programs\Git\Git Bash.lnk",
Arguments = "cd C:\\Users\\strit\\autocommittest2\\autocommittest2\n",
RedirectStandardOutput = true,
UseShellExecute = false,
CreateNoWindow = true,
}
};
process.Start();
string result = process.StandardOutput.ReadToEnd();
process.WaitForExit();
}
Git Bash opens but nothing is written in the command line.
I know it is old question, still adding answer as few days ago I was also facing same issue.
I think what you are missing is -c parameter. I used below code and it solved this issue. -c tells git-bash to execute whatever follows, it is similar to -cmd parameter in command line.
In below mentioned function -
fileName = path of git-bash.exe.
command = git command which you want to execute.
workingDir = Local path of git repository.
public static void ExecuteGitBashCommand(string fileName, string command, string workingDir)
{
ProcessStartInfo processStartInfo = new ProcessStartInfo(fileName, "-c \" " + command + " \"")
{
WorkingDirectory = workingDir,
RedirectStandardOutput = true,
RedirectStandardError = true,
RedirectStandardInput = true,
UseShellExecute = false,
CreateNoWindow = true
};
var process = Process.Start(processStartInfo);
process.WaitForExit();
string output = process.StandardOutput.ReadToEnd();
string error = process.StandardError.ReadToEnd();
var exitCode = process.ExitCode;
process.Close();
}
I hope it solves the issue.
I think you are on the right way. I would try to use the git in the path, but it should be possible to also use the git-bash.exe directly, at my machine it is located here: C:\Program Files\Git\git-bash.exe.
Process gitProcess = new Process();
gitInfo.Arguments = YOUR_GIT_COMMAND; // such as "fetch origin"
gitInfo.WorkingDirectory = YOUR_GIT_REPOSITORY_PATH;
gitInfo.UseShellExecute = false;
gitProcess.StartInfo = gitInfo;
gitProcess.Start();
string stderr_str = gitProcess.StandardError.ReadToEnd(); // pick up STDERR
string stdout_str = gitProcess.StandardOutput.ReadToEnd(); // pick up STDOUT
gitProcess.WaitForExit();
gitProcess.Close();
Like #S.Spieker already told you in it's good answer, no need to use git bash (it makes it harder to achieve and less performant), just call directly the git executable.
You could have a look to the GitExtensions code that is doing that: https://github.com/gitextensions/gitextensions/blob/027eabec3be497f8d780cc68ece268c64a43a7d5/GitExtensionsVSIX/Git/GitCommands.cs#L112
You could also achieve what you want using libgit2sharp (https://github.com/libgit2/libgit2sharp). That could be easier if you want to interpret the results of the command run.
I'm writing a c# application for validating the detailed information about no.of lines changes in SVN commit. After providing the below arguments in command prompt, it displays the revision number, author name and last changed date etc...
Argument:
svn info –r {revision no} {Source path}
Eg - svn info -r 113653 "F:\SVN"
I have to achieve the same in C# also. While giving the above arguments in C#, it should read the output(revision number, author name and last changed date) from the command prompt and store it in a string. I have tried the StandardOutput.ReadToEnd() but couldn't meet my requirement. Any detailed explanation will be helpful.
Have you tried just running the command from a command prompt with C# as explained in this question?
string strCmdText = #"/C svn info -r 113653 ""F:\SVN""";
System.Diagnostics.Process.Start("CMD.exe",strCmdText);
You can use the following method to run a command and retrieve the standard output from the console :
public static string StdOut(string args)
{
string cmdOut = "";
ProcessStartInfo startInfo = new ProcessStartInfo("cmd", "/C " + args)
{
WindowStyle = ProcessWindowStyle.Hidden,
UseShellExecute = false,
RedirectStandardOutput = true,
RedirectStandardError = true,
CreateNoWindow = true
};
cmdOut = ExecuteCommand(cmdOut, startInfo);
return cmdOut;
}
It will return the output as a string.
You will also need this method (as it is used in the above):
private static string ExecuteCommand(string cmdOut, ProcessStartInfo startInfo)
{
Process p = Process.Start(startInfo);
p.OutputDataReceived += (x, y) => cmdOut += y.Data;
p.BeginOutputReadLine();
p.BeginErrorReadLine();
p.WaitForExit();
return cmdOut;
}
p.OutputdataReceived is a DataReceivedEventHandler and it will concatenate any std output received onto the cmdOut variable.
I have a program in Debian which needs root privileges and myuser has to run it, but I have to do the call from a .NET application (C#) running in mono.
In /etc/sudoers, I have add the line:
myuser ALL = NOPASSWD: /myprogram
so sudo ./myprogram works for myuser.
In. NET I use in my code
string fileName = "/myprogram";
ProcessStartInfo info = new ProcessStartInfo (fileName);
...
How can I do the call "sudo fileName"? It doesn't work by the time...
thank you, Monique.
The following worked for me in a similar situation, and demonstrates passing in multiple arguments:
var psi = new ProcessStartInfo
{
FileName = "/bin/bash",
UseShellExecute = false,
RedirectStandardOutput = true,
Arguments = string.Format("-c \"sudo {0} {1} {2}\"", "/path/to/script", "arg1", arg2)
};
using (var p = Process.Start(psi))
{
if (p != null)
{
var strOutput = p.StandardOutput.ReadToEnd();
p.WaitForExit();
}
}
You just need to pass your program as the argument to the sudo command like this:
ProcessStartInfo info = new ProcessStartInfo("sudo", "/myprogram");
Process.Start(info);
I'd like to use C# to execute a shell script.
Based on similar questions I came to a solution that looks like this.
System.Diagnostics.Process.Start("/Applications/Utilities/Terminal.app","sunflow/sunflow.sh");
It currently opens Terminal, then opens the shell file with the default application (Xcode in my case). Changing the default application is not an option, since this app will need to be installed for other users.
Ideally the solution will allow for arguments for the shell file.
I can't test with a Mac right now, but the following code works on Linux and should work on a Mac because Mono hews pretty closely to Microsoft's core .NET interfaces:
ProcessStartInfo startInfo = new ProcessStartInfo()
{
FileName = "foo/bar.sh",
Arguments = "arg1 arg2 arg3",
};
Process proc = new Process()
{
StartInfo = startInfo,
};
proc.Start();
A few notes about my environment:
I created a test directory specifically to double-check this code.
I created a file bar.sh in subdirectory foo, with the following code:
#!/bin/sh
for arg in $*
do
echo $arg
done
I wrapped a Main method around the C# code above in Test.cs, and compiled with dmcs Test.cs, and executed with mono Test.exe.
The final output is "arg1 arg2 arg3", with the three tokens separated by newlines
Thanks Adam, it is good starting point for me. However, for some reason when I tried with above code (changed to my needs) I am getting below error
System.ComponentModel.Win32Exception: Exec format error
see below code that gives above error
ProcessStartInfo startInfo = new ProcessStartInfo()
{
FileName = "/Users/devpc/mytest.sh",
Arguments = string.Format("{0} {1} {2} {3} {4}", "testarg1", "testarg2", "testarg3", "testarg3", "testarg4"),
UseShellExecute = false,
RedirectStandardOutput = true,
CreateNoWindow = true
};
Process proc = new Process()
{
StartInfo = startInfo,
};
proc.Start();
while (!proc.StandardOutput.EndOfStream)
{
string result = proc.StandardOutput.ReadLine();
//do something here
}
and spent some time and come up with below and it is working in my case - just in case if anyone encounter this error try below
Working Solution:
var command = "sh";
var scriptFile = "/Users/devpc/mytest.sh";//Path to shell script file
var arguments = string.Format("{0} {1} {2} {3} {4}", "testarg1", "testarg2", "testarg3", "testarg3", "testarg4");
var processInfo = new ProcessStartInfo()
{
FileName = command,
Arguments = arguments,
UseShellExecute = false,
RedirectStandardOutput = true,
CreateNoWindow = true
};
Process process = Process.Start(processInfo); // Start that process.
while (!process.StandardOutput.EndOfStream)
{
string result = process.StandardOutput.ReadLine();
// do something here
}
process.WaitForExit();