当输入路径中有方括号时,Get-ChildItem -Recurse 是否被破坏? [英] Is Get-ChildItem -Recurse broken when there are square brackets in the input path?

查看:59
本文介绍了当输入路径中有方括号时,Get-ChildItem -Recurse 是否被破坏?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

好的,所以我觉得这一定是 PowerShell 中的一个错误,但我想看看你们是否认为这听起来很糟糕.这是一件很容易重现的事情,但我可以理解为什么它可能不是一个特别常见的用例.我在下面放置的步骤实际上并不是我的脚本在做什么,我实际上是在计算子文件夹的大小 - 我只是将其浓缩为最简单的可能显示我的问题的场景.

我只在 PowerShell 5.0.10240.16384 上尝试过这个,但可能很快就有机会在早期版本上测试它[我现在已经在 PowerShell 2.0 上测试了这个,错误确实存在没有出现在那个版本中 - 它按预期工作].只是一个简短的说明 - 我一直使用 gci 作为 Get-ChildItem 的缩写.如果您还不知道,这也适用于实际输入 PowerShell.但是无论您使用什么别名,问题都存在.

首先,在方便的地方创建一个名为 Test [123] 的文件夹.在该文件夹中,创建几个文件.我的被​​称为 Test1.txtTest2.txt.他们不需要任何东西.

接下来,打开 PowerShell 会话并将 Set-Location 设置为新 Test [123] 文件夹的父文件夹.

现在,运行 gci -Filter Test*,您应该会看到如下内容:

Mode LastWriteTime Length Name---- ------------- ------ ----d----- 11/15/2015 3:22 PM 测试 [123]

一切都很好,对吧?接下来,尝试 gci -Filter Test* |gci.这使得第一个 gci 的输出成为下一个 gci 的输入,即向我们展示第一个 gci 返回的每个项目的子项.这给了我们以下内容:

Mode LastWriteTime Length Name---- ------------- ------ -----a---- 11/14/2015 10:21 PM 0 Test1.txt-a---- 11/15/2015 下午 3:55 0 Test2.txt

再次,一切都很好 - 完全符合预期.这是我们 Test [123] 文件夹中的所有文件.

现在试试这个:gci -Filter Test* |gci -递归.我们所做的只是对 gci 的第二次调用现在是递归的,因此它应该向我们显示所有文件,包括子文件夹.我们没有任何子文件夹,所以我们期望得到相同的结果,对吗?

错了.我们根本没有得到任何输出.看起来很奇怪,我们所做的只是添加了 -Recurse,现在我们得到了不同的输出.我认为添加 -Recurse 不应该渲染更少的输出,只会更多.

这是下一件奇怪的事情.现在试试 gci -Filter Test* |gci -Recurse -Name.除了添加了 -Name 参数外,这与之前相同.这只是说我们想要相同的输出,除了我们只想要文件名而不是每个项目的完整信息.所以我们可能不期待任何回报.但这不是我们得到的,我们得到了这个:

Test1.txt测试2.txt

必须被打破,对吧?首先-Recurse不应该减少输出量,其次要求不同格式的输出不应该改变我们得到的输出量.

仅当文件夹名称中有方括号时才会发生这种情况.如果您创建另一个名为 Test 的文件夹,然后再次运行上述所有命令,您将始终看到 Test 文件夹中的文件.

我的研究使我找到了 -LiteralPath 参数;但是,将上述命令改写为 gci -Filter Test* |foreach { gci -Recurse -LiteralPath $_ },为了使用该参数,仍然不返回任何输出,并且再次添加-Name 参数开始再次返回的文件.

我已经设法解决了这个问题,使用 -Name 参数,然后将它与我正在搜索的文件夹的路径结合起来,然后将其传递给 Get-Item,但这使得代码比它需要的更长更丑.

所以我的问题是,我是否犯了错误或误解了什么?或者这是我应该报告的错误?

解决方案

TL;DR:当名称中可能存在异常字符(包括方括号)时,请使用 -LiteralPath 作为文件夹.

<小时>

我无法按照 PowerShell v5.1.17134.590 中的 OP 重现这一点.

但是,我能够重现类似的东西,使用以下命令尝试列出我怀疑为空的文件夹中的文件,以便将其删除.实际上,这个文件夹中有 12 个 .mp3 文件:

[PS]>gci '.\Music\Artist - Name\Album Name [Disc 1]\'[PS]>

添加 -Recurse 开关会导致 cmdlet 返回错误,而不是上面显示的(误导性的)空响应.我用 -Include * 选项测试了相同的命令,仍然没有结果,但是这次与 -Recurse 开关结合使用时没有错误.>

-文字路径

最适合我的是使用 -LiteralPath 参数指定路径:

[PS]>gci -LiteralPath '.\Music\Artist - Name\Album Name [Disc 1]\'

逃跑

为了涵盖其他一些可能的情况,您可能想要尝试对方括号进行转义.使用@PetSerAl 在 OP 评论中的建议,您可以尝试这样的操作:

[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``]\'

有关方括号的更多信息,请参阅以下问答.逃脱:

OK, so I feel like this must be a bug in PowerShell, but I wanted to see if you guys think this sounds broken. It's quite an easy thing to reproduce, but I can see why it might not be a particularly common use case. The steps I've put below aren't actually what my script was doing, I was actually calculating sizes of subfolders - I've just condensed it down to the simplest possible scenario that shows my problem.

I have only tried this on PowerShell 5.0.10240.16384, but might soon have the chance to test it on an earlier version [Edit: I have now tested this on PowerShell 2.0, and the bug does not appear in that version - it works as expected]. Just a quick note - I've used gci throughout as an abbreviation for Get-ChildItem. If you didn't already know, this works to actually type into PowerShell too. But the problem exists whatever alias you use.

First, create a folder called Test [123] somewhere handy. In that folder, create a couple of files. Mine are caled Test1.txt and Test2.txt. They don't need to have anything in them.

Next, open a PowerShell session and Set-Location to the parent folder of your new Test [123] folder.

Now, run gci -Filter Test* and you should see something like:

Mode                LastWriteTime         Length Name
----                -------------         ------ ----
d-----       11/15/2015   3:22 PM                Test [123]

All good, right? Next, try gci -Filter Test* | gci. This makes the output of the first gci the input for the next one, ie shows us the children of each item the first gci returns. This gives us the following:

Mode                LastWriteTime         Length Name
----                -------------         ------ ----
-a----       11/14/2015  10:21 PM              0 Test1.txt
-a----       11/15/2015   3:55 PM              0 Test2.txt

Again, all good - exactly as expected. This is all the files from our Test [123] folder.

Now try this: gci -Filter Test* | gci -Recurse. All we've changed is that the second call to gci is now recursive, so it should show us all files including subfolders. We don't have any subfolders, so we're expecting the same results, right?

Wrong. We don't get any output at all. Seems very odd that all we've done is added -Recurse and now we get different output. I think that adding -Recurse should never render less output, only ever more.

Here's the next weird thing. Now try gci -Filter Test* | gci -Recurse -Name. This is the same as before except with the -Name parameter added. This is simply saying that we want the same output, except we only want the filenames and not the full information about each item. So we're probably expecting nothing back. But that's not what we get, we get this:

Test1.txt
Test2.txt

This has got to be broken, right? Firstly -Recurse should never reduce the amount of output, and secondly asking for the output in a different format should not change the amount of output we get.

This only happens when there are square brackets in the name of the folder. If you create another folder, just called Test, and run all the commands above again, you will always see the files from the Test folder.

My research lead me to the -LiteralPath parameter; however, rephrasing the above command as gci -Filter Test* | foreach { gci -Recurse -LiteralPath $_ }, so as to use that parameter, still returns no output, and again, adding the -Name parameter starts the files being returned again.

I've managed to do a workaround for this, using the -Name parameter and then combining it with the path of the folder I'm searching, then passing that into Get-Item, but that's made the code longer and uglier than it needs to be.

So my question is, have I made a mistake or misunderstood something? Or is this a bug I should report?

解决方案

TL;DR: Use -LiteralPath for the folder when there might be unusual characters (inc. square brackets) in the names.


I wasn't able to reproduce this as per the OP in PowerShell v5.1.17134.590.

However, I was able to reproduce something similar, using the following command to attempt to list files in a folder I suspected was empty, in order to delete it. In actual fact, this folder had 12 .mp3 files in it:

[PS]> gci '.\Music\Artist - Name\Album Name [Disc 1]\'

[PS]>

Adding the -Recurse switch caused the cmdlet to return an error rather than the (misleading) empty response shown above. I tested the same command with the -Include * option, and still there were no results, however this time there was no error when combined with the -Recurse switch.

-LiteralPath

The thing that worked best for me was to specify the path with the -LiteralPath parameter:

[PS]> gci -LiteralPath '.\Music\Artist - Name\Album Name [Disc 1]\'

Escaping

To cover some other possible cases, you might want to try to escape the square brackets. Using the suggestion from @PetSerAl in the comments on the OP you could try something like this:

[PS]> [System.Management.Automation.WildcardPattern]::Escape('.\Music\Artist - Name\Album Name [Disc 1]\')

.\Music\Artist - Name\Album Name `[Disc 1`]\

Sadly, this didn't work straight away. I found that I needed to escape twice, and then the following command gave the correct directory listing:

[PS]> gci '.\Music\Artist - Name\Album Name ``[Disc 1``]\'

See the following Q&A for more about square brackets & escaping:

这篇关于当输入路径中有方括号时,Get-ChildItem -Recurse 是否被破坏?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆