Short version:
Is it enough to wrap the argument in quotes and escape \
and "
?
Code version
I want to pass the command line arguments string[] args
to another process using ProcessInfo.Arguments.
ProcessStartInfo info = new ProcessStartInfo();
info.FileName = Application.ExecutablePath;
info.UseShellExecute = true;
info.Verb = "runas"; // Provides Run as Administrator
info.Arguments = EscapeCommandLineArguments(args);
Process.Start(info);
The problem is that I get the arguments as an array and must merge them into a single string. An arguments could be crafted to trick my program.
my.exe "C:\Documents and Settings\MyPath \" --kill-all-humans \" except fry"
According to this answer I have created the following function to escape a single argument, but I might have missed something.
private static string EscapeCommandLineArguments(string[] args)
{
string arguments = "";
foreach (string arg in args)
{
arguments += " \"" +
arg.Replace ("\\", "\\\\").Replace("\"", "\\\"") +
"\"";
}
return arguments;
}
Is this good enough or is there any framework function for this?
It's more complicated than that though!
I was having related problem (writing front-end .exe that will call the back-end with all parameters passed + some extra ones) and so i looked how people do that, ran into your question. Initially all seemed good doing it as you suggest
arg.Replace (@"\", @"\\").Replace(quote, @"\"+quote)
.However when i call with arguments
c:\temp a\\b
, this gets passed asc:\temp
anda\\b
, which leads to the back-end being called with"c:\\temp" "a\\\\b"
- which is incorrect, because there that will be two argumentsc:\\temp
anda\\\\b
- not what we wanted! We have been overzealous in escapes (windows is not unix!).And so i read in detail http://msdn.microsoft.com/en-us/library/system.environment.getcommandlineargs.aspx and it actually describes there how those cases are handled: backslashes are treated as escape only in front of double quote.
There is a twist to it in how multiple
\
are handled there, the explanation can leave one dizzy for a while. I'll try to re-phrase said unescape rule here: say we have a substring of N\
, followed by"
. When unescaping, we replace that substring with int(N/2)\
and iff N was odd, we add"
at the end.The encoding for such decoding would go like that: for an argument, find each substring of 0-or-more
\
followed by"
and replace it by twice-as-many\
, followed by\"
. Which we can do like so:That's all...
PS. ... not. Wait, wait - there is more! :)
We did the encoding correctly but there is a twist because you are enclosing all parameters in double-quotes (in case there are spaces in some of them). There is a boundary issue - in case a parameter ends on
\
, adding"
after it will break the meaning of closing quote. Examplec:\one\ two
parsed toc:\one\
andtwo
then will be re-assembled to"c:\one\" "two"
that will me (mis)understood as one argumentc:\one" two
(I tried that, i am not making it up). So what we need in addition is to check if argument ends on\
and if so, double the number of backslashes at the end, like so:I wrote you a small sample to show you how to use escape chars in command line.
And here is a test method:
The point is to to wrap each arg with double-double quotes ( ""arg"" ) and to replace all quotes inside arg value with escaped quote ( test\"123 ).