给 C# 程序的命令行参数被解析错误

command line arguments given to a C# program are parsed wrong

我写了一个小程序,例如下面的命令行:

prog.exe -p -z "E:\temp.zip" -v "f:\" -r -o -s –c
prog.exe -p -z "E:\temp.zip" -v f:\ -r -o -s –c
prog.exe -p -z "E:\temp.zip" -v "f:\log" -r -o -s –c

此命令行由另一个程序生成,该程序会自动在文件名和路径名两边插入引号,以防止将空格识别为参数分隔符。

第一个命令行随后被 .Net 框架解析为:

args     {string[5]}        string[]
[0]        "-p"      string
[1]        "-z"      string
[2]        "f:\temp.zip"   string
[3]        "-v"      string
[4]        "f:\" -r -o -s -c" string

但应该是(第二个命令行的结果):

args      {string[9]}          string[]
[0]        "-p"                string
[1]        "-z"                string
[2]        "f:\temp.zip"      string
[3]        "-v"                string
[4]        "f:\"              string
[5]        "-r"                string
[6]        "-o"                string
[7]        "-s"                string
[8]        "-c"                string

一个可能的解决方案是检查调用应用程序中的文件名和路径名是否包含空格,然后才在名称两边加上引号。

但是还有别的解决办法吗?

我创建了一个可以显示命令行参数的小批处理文件。使用您的第一个命令行,我得到

1 -p
2 -z
3 "E:\temp.zip"
4 -v
5 "f:\"
6 -r
7 -o
8 -s
9 –c

这是应该的。如果 .NET 以不同的方式解析它,那将是一个主要错误。只是为了检查,我创建了一个测试控制台应用程序。结果是:

0  -p
1  -z
2  E:\temp.zip
3  -v
4  f:" -r -o -s -c

我不认为这是可能的!所以我研究了一下,然后我得到了这个 link: Everyone quotes command line arguments the wrong way which explains why the command line parser is essentially flawed. (I know it's for C++, but it applies) which led me to the rules of parsing for command line parameters which says \" is interpreted as an escaped quote, as opposite how the operating system sees it (which is gross) .

结论:如果你想修复命令行,你需要在引号前转义斜杠,所以你需要 "f:\" 而不是 "f:\"。另一种解决方案是使用 Environment.CommandLine which gets you the entire command line, executable included, and you can parse it yourself. More on this here: Getting raw (unsplit) command line in .NET.

为了完整起见,我将其放入:Split string containing command-line parameters into string[] in C#,其中讨论了如何使用系统函数将命令行字符串拆分为参数。

After some more research, I realized that there are several standards of command line argument parsing, depending on compiler and operating system and its version, and that the only way to be consistent is to parse the raw command line yourself.

例如,在 Environment.CommandLine 上使用 CommandLineToArgvW 完全复制了对 Environment.GetCommandLineArgs() 的调用,returns 与提供给 Main 方法的 args 数组完全相同。

我找到了一个关于这个问题的非常详细的页面:http://daviddeley.com/autohotkey/parameters/parameters.htm 我相信这是命令行解析一般问题的最终答案。