用于转义.NET命令行参数的规范解决方案



问题:给定一个文件名和任意字符串列表,是否有规范的方法来创建单个命令行,以便Environment.GetCommandLineArgs(和C#的void main(String[] args)/VB的Sub Main(args() As String))将返回相同的字符串列表?


背景:.NET将命令行拆分为参数的方式异常复杂,例如:

如果一个双引号跟在两个或偶数个反斜杠后面,则每个正在进行的反斜杠对将被一个反斜杠替换,并且双引号将被删除。如果一个双引号跟在奇数个反斜杠后面,其中只有一个,则前面的每一对反斜杠都会被一个反斜杠替换,剩下的反斜杠也会被删除;但是,在这种情况下,不会删除双引号。

许多人尝试简单的"将每个参数放在双引号中并转义现有的双引号"方法,一旦其中一个参数包含尾部反斜杠,就会失败。关于这个问题,StackOverflow上有各种各样的问题,例如:

  • 如何转义包含空格的路径
  • c中的转义命令行参数#
  • Process.Start的转义字符串
  • 在C中传递命令行参数#

然而,他们的答案要么不够通用,无法为所有情况提供规范的解决方案,要么似乎是"迭代式"开发的("哦,我忘了还有一个特殊情况,让我们添加它,现在它应该涵盖大多数情况…")

  • 来自权威来源(可能是参与这个疯狂命令行约定的开发人员的博客条目),或者
  • 提供了给定算法满足.NET命令行要求的形式证明

此算法是通用的,来自相对权威的来源(MSDN博客)。

几年前,微软宣布他们将在CodePlex上发布一个命令行解析器(而不是.NET Framework 4附带的System.Shell.CommonLine)。我不确定他们是否真的这么做了。如果您想要一个由Microsoft员工开发的解析器,请查看cmdline。您还可以在CodePlex中查找命令行解析。

你也可以试试Mono.Options,它非常强大。

从.NET Core 2.1开始,不再需要手动转义命令行参数:ProcessStartInfo现在有了ArgumentList属性,并自动处理所需的任何转义。

引用文档中的示例:

var info = new System.Diagnostics.ProcessStartInfo("cmd.exe");
info.ArgumentList.Add("/c");
info.ArgumentList.Add("dir");
info.ArgumentList.Add(@"C:Program Filesdotnet"); // there is no need to escape the space, the API takes care of it

在这里,你可以看到该算法的辉煌(包括著名的"2n+1反斜杠规则")。它获得了麻省理工学院的许可,如果需要的话,可以很容易地将其移植到.NET Framework 4.8项目中。

  • https://github.com/dotnet/runtime/blob/main/src/libraries/System.Private.CoreLib/src/System/PasteArguments.cs

相关内容

最新更新