Running complex command line from C# - c#

I'm trying to run the following command line from C#:
Process.Start("C:\\Program Files\\GoToTags\\GoToTags Encoder\\GoToTags.Encoder.exe --records "{'Url':'http://petshop.intato.com/index.php?id='" + TxtBoxIDCode.Text + "'','RecordType':'Website'}"");
Obviously it is not working.
The problem is that I need to keep the proper signs such as the : in order to make it work properly.
The original command is:
C:\Program Files\GoToTags\GoToTags Encoder\GoToTags.Encoder.exe --records "{'Url':'http://petshop.intato.com/index.php?id=29','RecordType':'Website'}"
I have to run that command and at the same time, replace that 29 with the content of a textbox
Would anyone be able to help me with that?

The string.Format command is your friend...
string path = #"C:\Program Files\GoToTags\GoToTags Encoder\GoToTags.Encoder.exe";
string args = string.Format("--records \"{'Url':'http://petshop.intato.com/index.php?id={0}','RecordType':'Website'}\"", TxtBoxIDCode.Text);
Process.Start(path, args);

You have several pitfalls awaiting you.
Firstly, as you've already discovered, the backslashes in path names cause problems in the strings, as they could also indicate C# escape sequences. It's usually good practice to use C#'s #"..." syntax for file names, partly to avoid needing to double up the backslashes and make it easier to read, and partly because you could inadvertently leave a \t in there and it'd go unnoticed for ages.
Secondly, the single-parameter call to Process.Start only takes a command - it cannot accept command arguments - so you have to call the two-parameter overload.
Thirdly, the quotes around of the value of the records argument need handling so that the C# syntax knows what you want with them - i.e. to pass them to the command. I've separated out the command arguments into two parts to make that clearer. I have elected to use backslashes to escape them, though using the alternative #"...""..." would be just as good, and the choice is largely down to personal preference unless the context points you strongly one way rather than the other.
string cmd = #"C:\Program Files\GoToTags\GoToTags Encoder\GoToTags.Encoder.exe";
string url = "http://petshop.intato.com/index.php?id=" + TxtBoxIDCode.Text;
string cmdArgs = "--records \"{'Url':'" + url + "','RecordType':'Website'}\"";
Process.Start(cmd, cmdArgs);
[edited to add:]
If for some reason you find you either want or need to use string.Format to help build your cmdArgs, there's a fourth gotcha waiting in the wings for you, in that string.Format looks for the brace ({ and }) characters to delimit insertion parameter specifications, but your records command-line argument wants braces characters in the string. The way to achieve that would be to double up the braces that you want, like this:
string cmdArgs =
string.Format("--records \"{{'Url':'{0}','RecordType':'Website'}}\", url)";

In addition to the other answers, you should use the two-argument overload of Process.Start. The first argument is the executable, and the second argument is the command line arguments.
Normally, if you insist on using a single argument call, you should enclose your executable in double quotes, as such:
"\"C:\\Program Files\\GoToTags\\GoToTags Encoder\\GoToTags.Encoder.exe\" ...arguments here..."
However, this form does not work for Process.Start(string) because it specifically disallows it.

Related

Any way to use string (without escaping manually) that contains double quotes

Let's say I want to assign a text (which contains many double quotes) into variable. However, the only way seems to manually escape:
string t = "Lorem \"Ipsum\" dummy......
//or//
string t = #"Lorem ""Ipsum"" dummy.....
Is there any way to avoid manual escaping, and instead use something universal (which I dont know in C#) keywoard/method to do that automatically? In PHP, it's untoldly simple, by just using single quote:
$t = 'Lorem "Ipsum" dummy .......
btw, please don't bomb me with critiques "Why do you need to use that" or etc. I need answer to the question what I ask.
I know this answer may not be satisfying, but C# sytnax simply won't allow you to do such thing (at the time of writing this answer).
I think the best solution is to use resources. Adding/removing and using strings from resources is super easy:
internal class Program
{
private static void Main(string[] args)
{
string myStringVariable = Strings.MyString;
Console.WriteLine(myStringVariable);
}
}
The Strings is the name of the resources file without the extension (resx):
MyString is the name of your string in the resources file:
I may be wrong, but I conjecture this is the simplest solution.
No. In C# syntax, the only way to define string literals is the use of the double quote " with optional modifiers # and/or $ in front. The single quote is the character literal delimiter, and cannot be used in the way PHP would allow - in any version, including the current 8.0.
Note that the PHP approach suffers from the need to escape ' as well, which is, especially in the English language, frequently used as the apostrophe.
To back that up, the EBNF of the string literal in current C# is still this:
regular_string_literal '"' { regular_string_literal_character } '"'
The only change in the compiler in version 8.0 was that now, the order of the prefix modifiers $ (interpolated) and # (verbatim) can be either #$ or $#; it used to matter annoyingly in earlier versions.
Alternatives:
Save it to a file and use File.ReadAllText for the assignment, or embed it as a managed ressource, then the compiler will provide a variable in the namespace of your choice with the verbatim text as its runtime value.
Or use single quotes (or any other special character of your choice), and go
var t = #"Text with 'many quotes' inside".Replace("'", #"""");
where the Replace part could be modeled as an extension to the String class for brevity.

How do you put quotes around variables when using complex commands and C# interpolation?

I am trying to perform a Robocopy of a file. The command I'm using (below) works when the "filename" variable does not contain spaces. How can I write this command to ignore spaces in this variable?
System.Diagnostics.Process.Start("robocopy.exe",
$#"X: ""C:\users\username\desktop\test"" {filename}").WaitForExit();
Please See my comments below (i.e.; dguth8)
I found the solution for this myself. Just in case anyone else is trying something similar, here's the command I had to use:
Note: Essentially, I had to combine the 3 arguments for Robocopy into a single string, then use the approach addressed in the other question "How do you handle spaces in variables when using C# interpolation?", meaning escaping quotes around the variable.
System.Diagnostics.Process.Start("robocopy.exe", $"X:\ C:\\users\\usersname\\Desktop\\FolderName \"{filename}\"").WaitForExit();

Console Application input parameters - string identification

I have a console app that takes in string parameters. The app runs through the command line like so:
C:\ExampleApp.exe this is a "test"
In the above example, there are 4 different strings read in as parameters.. Is there any way to determine which parameter had quotes around it? When I do a Console.WriteLine(args[3]), it prints out as test and not "test".
Environment.CommandLine
returns a complete command line as a single string, just parse it and you will get the original parameters, quoted or not.
As far as I know the quotes are stripped by the framework before beeing passed to your main function, have you tried to escape the qoutes using a backslash?

Spaces and backslashes in Visual Studio build events

I have an application that is supposed to aid my project in terms of pre- and post-build event handling. I'm using ndesk.options for command line argument parsing. Which gave me weird results when my project path contains spaces. I thought this was the fault of ndesk.options but I guess my own application is to blame. I call my application as a post-built event like so:
build.exe --in="$(ProjectDir)" --out="c:\out\"
A simple foreach over args[] displays the following:
--in=c:\my project" --out=c:\out"
What happened is that the last " in each parameter was treated as if it was escaped. Thus the trailing backslash was removed. And the whole thing is treated as a single argument.
Now I thought I was being smart by simply escaping the first " as well, like so:
build.exe --in=\"$(ProjectDir)" --out=\"c:\out\"
In that case the resulting args[] look like this:
--path="c:\my
project"
--out="c:\out"
The trailing backslash in the parameters is still swallowed and the first parameter is now split up.
Passing this args[] to ndesk.options will then yield wrong results.
How should the right command line look so that the correct elements end up in the correct args[] slots? Alternatively, how is one supposed to parse command line arguments like these with or without ndesk.options? Any suggestion is welcome.
Thanks in advance
Did you try to escape the last backslash?
build.exe --in="$(ProjectDir)\" --out="c:\out\\"
This works probably only, as long as the ProjectDir ends in \, which should be given.
This is just an idea, but I did not give it a try
EDIT:
I found a comment which suggests to leave out the trailing "
I actually used "." to solve this same problem:
build.exe --in="$(ProjectDir)." --out="c:\out\."
primarily because otherwise it might look like you are trying to escape the second quote...which you're not, you're escaping the final \ (which is hidden).
I also added a REM in the postbuild command describing why I did that.

Declaring a looooong single line string in C#

Is there a decent way to declare a long single line string in C#, such that it isn't impossible to declare and/or view the string in an editor?
The options I'm aware of are:
1: Let it run. This is bad because because your string trails way off to the right of the screen, making a developer reading the message have to annoying scroll and read.
string s = "this is my really long string. this is my really long string. this is my really long string. this is my really long string. this is my really long string. this is my really long string. this is my really long string. this is my really long string. ";
2: #+newlines. This looks nice in code, but introduces newlines to the string. Furthermore, if you want it to look nice in code, not only do you get newlines, but you also get awkward spaces at the beginning of each line of the string.
string s = #"this is my really long string. this is my long string.
this line will be indented way too much in the UI.
This line looks silly in code. All of them suffer from newlines in the UI.";
3: "" + ... This works fine, but is super frustrating to type. If I need to add half a line's worth of text somewhere I have to update all kinds of +'s and move text all around.
string s = "this is my really long string. this is my long string. " +
"this will actually show up properly in the UI and looks " +
"pretty good in the editor, but is just a pain to type out " +
"and maintain";
4: string.format or string.concat. Basically the same as above, but without the plus signs. Has the same benefits and downsides.
Is there really no way to do this well?
There is a way. Put your very long string in resources. You can even put there long pieces of text because it's where the texts should be. Having them directly in code is a real bad practice.
If you really want this long string in the code, and you really don't want to type the end-quote-plus-begin-quote, then you can try something like this.
string longString = #"Some long string,
with multiple whitespace characters
(including newlines and carriage returns)
converted to a single space
by a regular expression replace.";
longString = Regex.Replace(longString, #"\s+", " ");
If using Visual Studio
Tools > Options > Text Editor > All Languages > Word Wrap
I'm sure any other text editor (including notepad) will be able to do this!
It depends on how the string is going to wind up being used. All the answers here are valid, but context is important. If long string "s" is going to be logged, it should be surrounded with a logging guard test, such as this Log4net example:
if (log.IsDebug) {
string s = "blah blah blah" +
// whatever concatenation you think looks the best can be used here,
// since it's guarded...
}
If the long string s is going to be displayed to a user, then Developer Art's answer is the best choice...those should be in resource file.
For other uses (generating SQL query strings, writing to files [but consider resources again for these], etc...), where you are concatenating more than just literals, consider StringBuilder as Wael Dalloul suggests, especially if your string might possibly wind up in a function that just may, at some date in the distant future, be called many many times in a time-critical application (All those invocations add up). I do this, for example, when building a SQL query where I have parameters that are variables.
Other than that, no, I don't know of anything that both looks pretty and is easy to type (though the word wrap suggestion is a nice idea, it may not translate well to diff tools, code print outs, or code review tools). Those are the breaks. (I personally use the plus-sign approach to make the line-wraps neat for our print outs and code reviews).
you can use StringBuilder like this:
StringBuilder str = new StringBuilder();
str.Append("this is my really long string. this is my long string. ");
str.Append("this is my really long string. this is my long string. ");
str.Append("this is my really long string. this is my long string. ");
str.Append("this is my really long string. this is my long string. ");
string s = str.ToString();
You can also use: Text files, resource file, Database and registry.
Does it have to be defined in the source file? Otherwise, define it in a resource or config file.
Personally I would read a string that big from a file perhaps an XML document.
You could use StringBuilder
For really long strings, I'd store it in XML (or a resource). For occasions where it makes sense to have it in the code, I use the multiline string concatenation with the + operator. The only place I can think of where I do this, though, is in my unit tests for code that reads and parses XML where I'm actually trying to avoid using an XML file for testing. Since it's a unit test I almost always want to have the string right there to refer to as well. In those cases I might segregate them all into a #region directive so I can show/hide it as needed.
I either just let it run, or use string.format and write the string in one line (the let it run method) but put each of the arguments in new line, which makes it either easier to read, or at least give the reader some idea what he can expect in the long string without reading it in detail.
Use the Project / Properties / Settings from the top menu of Visual Studio. Make the scope = "Application".
In the Value box you can enter very long strings and as a bonus line feeds are preserved. Then your code can refer to that string like this:
string sql = Properties.Settings.Default.xxxxxxxxxxxxx;

Categories