为什么PowerShell在命令行上处理空字符串的方式不同?

Mic*_*ens 6 powershell executable command-line

这个问题类似于使用powershell将空参数传递给可执行文件,但我想扩展问题和答案并更好地理解"为什么",因为它似乎是一个PowerShell陷阱.

如果加载PSCX并运行echoargs(外部命令,即exe文件),您可以看到跳过空字符串参数:

PS> echoargs word "two words" "" 123
Arg 0 is <word>
Arg 1 is <two words>
Arg 2 is <123>
Run Code Online (Sandbox Code Playgroud)

但是如果你使用"CMD escape"(--%),你可以使它显示为"正确":

PS> echoargs --% word "two words" "" 123
Arg 0 is <word>
Arg 1 is <two words>
Arg 2 is <>
Arg 3 is <123>
Run Code Online (Sandbox Code Playgroud)

类似地,如果编写PowerShell函数,则正确处理空字符串:

PS> Show-Args word "two words" "" 123
Arg 0 is <word>
Arg 1 is <two words>
Arg 2 is <>
Arg 3 is <123>
Run Code Online (Sandbox Code Playgroud)

由于以下原因,这种差异对我来说似乎很重要.上面显示的示例在命令行上使用了一个文字空字符串,所以至少你有一个问题的提示.但是如果使用包含空字符串的变量,结果完全相同.这意味着必须要么:

  1. 严格控制所有变量被输入外部命令,或
  2. 使用CMD转义( - %)并放弃使用线路其余部分的任何PowerShell构造
  3. 引用带有反引号/双引号的外部命令的每个参数,如`"this`"或`"$this`"或`"`"

......或者坏事会发生!

(@KeithHill指出了上面的第三个解决方法,所以我在那里添加它是为了完整性.它适用于文字或变量,所以,尽管丑陋,可能是三种解决方法中的最佳选择.)

因此,PowerShell处理函数的参数与外部命令的参数不同 - 显着如此.这是PowerShell行为的不一致吗?如果没有,为什么不呢?


附录

作为参考,这是上面使用的PowerShell函数体:

function Show-Args()
{
    for ($i = 0; $i -lt $args.length; $i++)
    {
        Write-Host ("Arg {0} is <{1}>" -f $i, $args[$i])
    }   
}
Run Code Online (Sandbox Code Playgroud)

这里有一个与C#相同的echoargs:

class Program
{
    static void Main(string[] args)
    {
        for (int i = 0; i < args.Length; i++)
        {
            System.Console.WriteLine("Arg {0} is <{1}>", i, args[i]);
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

Jas*_*irk 2

这种行为可能被认为是“设计使然”(根据实现和测试很难确定),但我认为这个问题没有得到太多考虑,并且您提出了很好的观点。

我个人认为你是对的,PowerShell 不一致。值得考虑进行一致的更改,尽管这存在破坏现有脚本的风险。