输入路径中有方括号时,Get-ChildItem -Recurse 是否中断?
Is Get-ChildItem -Recurse broken when there are square brackets in the input path?
好的,所以我觉得这 一定 是 PowerShell 中的一个错误,但我想看看你们是否认为这听起来很糟糕。这是一件很容易重现的事情,但我明白为什么它可能不是一个特别常见的用例。我在下面提出的步骤实际上并不是我的脚本在做什么,我实际上是在计算子文件夹的大小 - 我只是将它浓缩为显示我的问题的最简单的可能场景。
我只在 PowerShell 5.0.10240.16384 上尝试过,但可能很快就有机会在早期版本上测试它 [编辑: 我现在已经在 PowerShell 2.0 上测试过,并且该错误 未 出现在该版本中 - 它按预期工作]。快速说明 - 我一直使用 gci
作为 Get-ChildItem 的缩写。如果您还不知道,这也适用于实际键入 PowerShell。但是无论您使用什么别名,问题都存在。
首先,在方便的地方创建一个名为 Test [123]
的文件夹。在该文件夹中,创建几个文件。我的名字是 Test1.txt
和 Test2.txt
。他们不需要有任何东西。
接下来,打开 PowerShell 会话并Set-Location
到新 Test [123]
文件夹的 父文件夹。
现在,运行 gci -Filter Test*
你应该会看到如下内容:
Mode LastWriteTime Length Name
---- ------------- ------ ----
d----- 11/15/2015 3:22 PM Test [123]
还好吧?接下来,尝试 gci -Filter Test* | gci
。这使得第一个 gci 的输出成为下一个 gci 的输入,即向我们展示第一个 gci returns 每个项目的子项。这给了我们以下信息:
Mode LastWriteTime Length Name
---- ------------- ------ ----
-a---- 11/14/2015 10:21 PM 0 Test1.txt
-a---- 11/15/2015 3:55 PM 0 Test2.txt
再一次,一切都很好 - 完全符合预期。这是我们 Test [123]
文件夹中的所有文件。
现在试试这个:gci -Filter Test* | gci -Recurse
。我们所做的只是对 gci
的第二次调用现在是递归的,因此它应该向我们显示所有文件,包括子文件夹。我们没有任何子文件夹,所以我们期待相同的结果,对吗?
错了。我们根本没有得到任何输出。看起来很奇怪,我们所做的一切都添加了 -Recurse
,现在我们得到了不同的输出。我认为添加 -Recurse
永远不会呈现 less 输出,只会呈现更多。
这是下一个奇怪的事情。现在尝试 gci -Filter Test* | gci -Recurse -Name
。这与之前相同,只是添加了 -Name
参数。这只是说我们想要相同的输出,除了我们只想要文件名而不是关于每个项目的完整信息。所以我们可能不期待任何回报。但这不是我们得到的,我们得到这个:
Test1.txt
Test2.txt
这得坏了,对吧?首先 -Recurse
不应该减少输出量,其次要求以不同格式输出不应该改变我们得到的输出量。
只有当文件夹名称中有方括号时才会出现这种情况。如果您创建另一个名为 Test
的文件夹,然后再次 运行 上述所有命令,您将始终看到 Test
文件夹中的文件。
我的研究让我找到了 -LiteralPath
参数;但是,将上述命令改写为 gci -Filter Test* | foreach { gci -Recurse -LiteralPath $_ }
,以便使用该参数,仍然 returns 没有输出,并且再次添加 -Name
参数开始再次返回文件。
我设法解决了这个问题,使用 -Name
参数,然后将它与我正在搜索的文件夹的路径结合起来,然后将其传递到 Get-Item
,但是这使得代码比它需要的更长更丑陋。
所以我的问题是,我是不是弄错了或误解了什么?或者这是我应该报告的错误?
似乎报告了错误 here 或非常相似的问题。
TL;DR:当名称中可能包含不寻常的字符(包括方括号)时,对文件夹使用 -LiteralPath
。
我无法按照 PowerShell v5.1.17134.590 中的 OP 重现此内容。
但是,我能够重现类似的东西,使用以下命令尝试列出我怀疑是空的文件夹中的文件,以便将其删除。事实上,这个文件夹中有 12 .mp3
个文件:
[PS]> gci '.\Music\Artist - Name\Album Name [Disc 1]\'
[PS]>
添加 -Recurse
开关导致 cmdlet return 出现错误,而不是上面显示的(误导性的)空响应。我用 -Include *
选项测试了相同的命令,仍然没有结果,但是这次与 -Recurse
开关结合使用时没有错误。
-文字路径
最适合我的方法是使用 -LiteralPath
参数指定路径:
[PS]> gci -LiteralPath '.\Music\Artist - Name\Album Name [Disc 1]\'
转义
为了涵盖其他一些可能的情况,您可能想尝试转义方括号。在 OP 的评论中使用@PetSerAl 的建议,您可以尝试这样的事情:
[PS]> [System.Management.Automation.WildcardPattern]::Escape('.\Music\Artist - Name\Album Name [Disc 1]\')
.\Music\Artist - Name\Album Name `[Disc 1`]\
遗憾的是,这并没有立即奏效。我发现我需要转义两次,然后下面的命令给出了正确的目录列表:
[PS]> gci '.\Music\Artist - Name\Album Name ``[Disc 1``]\'
有关方括号和转义的更多信息,请参阅以下问答:
好的,所以我觉得这 一定 是 PowerShell 中的一个错误,但我想看看你们是否认为这听起来很糟糕。这是一件很容易重现的事情,但我明白为什么它可能不是一个特别常见的用例。我在下面提出的步骤实际上并不是我的脚本在做什么,我实际上是在计算子文件夹的大小 - 我只是将它浓缩为显示我的问题的最简单的可能场景。
我只在 PowerShell 5.0.10240.16384 上尝试过,但可能很快就有机会在早期版本上测试它 [编辑: 我现在已经在 PowerShell 2.0 上测试过,并且该错误 未 出现在该版本中 - 它按预期工作]。快速说明 - 我一直使用 gci
作为 Get-ChildItem 的缩写。如果您还不知道,这也适用于实际键入 PowerShell。但是无论您使用什么别名,问题都存在。
首先,在方便的地方创建一个名为 Test [123]
的文件夹。在该文件夹中,创建几个文件。我的名字是 Test1.txt
和 Test2.txt
。他们不需要有任何东西。
接下来,打开 PowerShell 会话并Set-Location
到新 Test [123]
文件夹的 父文件夹。
现在,运行 gci -Filter Test*
你应该会看到如下内容:
Mode LastWriteTime Length Name
---- ------------- ------ ----
d----- 11/15/2015 3:22 PM Test [123]
还好吧?接下来,尝试 gci -Filter Test* | gci
。这使得第一个 gci 的输出成为下一个 gci 的输入,即向我们展示第一个 gci returns 每个项目的子项。这给了我们以下信息:
Mode LastWriteTime Length Name
---- ------------- ------ ----
-a---- 11/14/2015 10:21 PM 0 Test1.txt
-a---- 11/15/2015 3:55 PM 0 Test2.txt
再一次,一切都很好 - 完全符合预期。这是我们 Test [123]
文件夹中的所有文件。
现在试试这个:gci -Filter Test* | gci -Recurse
。我们所做的只是对 gci
的第二次调用现在是递归的,因此它应该向我们显示所有文件,包括子文件夹。我们没有任何子文件夹,所以我们期待相同的结果,对吗?
错了。我们根本没有得到任何输出。看起来很奇怪,我们所做的一切都添加了 -Recurse
,现在我们得到了不同的输出。我认为添加 -Recurse
永远不会呈现 less 输出,只会呈现更多。
这是下一个奇怪的事情。现在尝试 gci -Filter Test* | gci -Recurse -Name
。这与之前相同,只是添加了 -Name
参数。这只是说我们想要相同的输出,除了我们只想要文件名而不是关于每个项目的完整信息。所以我们可能不期待任何回报。但这不是我们得到的,我们得到这个:
Test1.txt
Test2.txt
这得坏了,对吧?首先 -Recurse
不应该减少输出量,其次要求以不同格式输出不应该改变我们得到的输出量。
只有当文件夹名称中有方括号时才会出现这种情况。如果您创建另一个名为 Test
的文件夹,然后再次 运行 上述所有命令,您将始终看到 Test
文件夹中的文件。
我的研究让我找到了 -LiteralPath
参数;但是,将上述命令改写为 gci -Filter Test* | foreach { gci -Recurse -LiteralPath $_ }
,以便使用该参数,仍然 returns 没有输出,并且再次添加 -Name
参数开始再次返回文件。
我设法解决了这个问题,使用 -Name
参数,然后将它与我正在搜索的文件夹的路径结合起来,然后将其传递到 Get-Item
,但是这使得代码比它需要的更长更丑陋。
所以我的问题是,我是不是弄错了或误解了什么?或者这是我应该报告的错误?
似乎报告了错误 here 或非常相似的问题。
TL;DR:当名称中可能包含不寻常的字符(包括方括号)时,对文件夹使用 -LiteralPath
。
我无法按照 PowerShell v5.1.17134.590 中的 OP 重现此内容。
但是,我能够重现类似的东西,使用以下命令尝试列出我怀疑是空的文件夹中的文件,以便将其删除。事实上,这个文件夹中有 12 .mp3
个文件:
[PS]> gci '.\Music\Artist - Name\Album Name [Disc 1]\'
[PS]>
添加 -Recurse
开关导致 cmdlet return 出现错误,而不是上面显示的(误导性的)空响应。我用 -Include *
选项测试了相同的命令,仍然没有结果,但是这次与 -Recurse
开关结合使用时没有错误。
-文字路径
最适合我的方法是使用 -LiteralPath
参数指定路径:
[PS]> gci -LiteralPath '.\Music\Artist - Name\Album Name [Disc 1]\'
转义
为了涵盖其他一些可能的情况,您可能想尝试转义方括号。在 OP 的评论中使用@PetSerAl 的建议,您可以尝试这样的事情:
[PS]> [System.Management.Automation.WildcardPattern]::Escape('.\Music\Artist - Name\Album Name [Disc 1]\')
.\Music\Artist - Name\Album Name `[Disc 1`]\
遗憾的是,这并没有立即奏效。我发现我需要转义两次,然后下面的命令给出了正确的目录列表:
[PS]> gci '.\Music\Artist - Name\Album Name ``[Disc 1``]\'
有关方括号和转义的更多信息,请参阅以下问答: