Windows:使用文件名正则表达式进行文件复制/移动?


10

我基本上到运行:

C:\>xcopy [0-9]{13}\.(gif|jpg|png) s:\TargetFolder /s

我知道xcopy不支持正则表达式文件名搜索。

我不知道如何找出PowerShell是否具有Cmdlet复制文件;以及是否支持正则表达式文件名匹配。

谁能想到一种使用正则表达式文件名匹配来执行递归文件复制/移动的方法吗?


1
这应该移到stackoverflow了吗?
user33788 2010年

1
@smoknheap:可能两者兼有,我发现Powershell脚本越来越成为Power User工具。这更多的是xcopy替换问题,而不是脚本问题。
Doltknuckle

Answers:


5

我喜欢在可能的情况下使用所有Powershell命令。经过一点测试,这是我能做的最好的。

$source = "C:\test" 
$destination = "C:\test2" 
$filter = [regex] "^[0-9]{6}\.(jpg|gif)"

$bin = Get-ChildItem -Path $source | Where-Object {$_.Name -match $filter} 
foreach ($item in $bin) {Copy-Item -Path $item.FullName -Destination $destination}

前三行只是为了使它更易于阅读,您可以根据需要在实际命令中定义变量。此代码示例的关键是“ Where-Object”命令,该命令是一个接受正则表达式匹配的过滤器。应该注意的是,对正则表达式的支持有些奇怪。我在这里找到了PDF参考卡该参考卡的左侧带有受支持的字符。

[编辑]

如“ @JohannesRössel”所述,您还可以将最后两行减少为一行。

((Get-ChildItem -Path $source) -match $filter) | Copy-Item -Destination $destination

主要区别在于Johannes的方法进行对象过滤,而我的方法进行文本过滤。使用Powershell时,使用对象几乎总是更好。

[EDIT2]

正如@smoknheap所提到的,以上脚本将整理文件夹结构并将所有文件放在一个文件夹中。我不确定是否有保留文件夹结构的开关。我尝试了-Recurse开关,但没有帮助。使它起作用的唯一方法是返回字符串操作并将文件夹添加到我的过滤器中。

$bin = Get-ChildItem -Path $source -Recurse | Where-Object {($_.Name -match $filter) -or ($_.PSIsContainer)}
foreach ($item in $bin) {
    Copy-Item -Path $item.FullName -Destination $item.FullName.ToString().Replace($source,$destination).Replace($item.Name,"")
    }

我敢肯定有一种更优雅的方法可以做到这一点,但是从我的测试来看,它是可行的。它收集所有内容,然后过滤名称匹配和文件夹对象。我必须使用ToString()方法来访问字符串操作。

[EDIT3]

现在,如果您要报告路径,以确保一切正确。您可以使用“写入主机”命令。这是将为您提供提示的代码。

cls
$source = "C:\test" 
$destination = "C:\test2" 
$filter = [regex] "^[0-9]{6}\.(jpg|gif)"

$bin = Get-ChildItem -Path $source -Recurse | Where-Object {($_.Name -match $filter) -or ($_.PSIsContainer)}
foreach ($item in $bin) {
    Write-Host "
----
Obj: $item
Path: "$item.fullname"
Destination: "$item.FullName.ToString().Replace($source,$destination).Replace($item.Name,"")
    Copy-Item -Path $item.FullName -Destination $item.FullName.ToString().Replace($source,$destination).Replace($item.Name,"")
    }

这应该返回相关的字符串。如果您什么都没找到,就会知道哪个项目有问题。

希望这可以帮助


请注意,您不需要在$item.FullName那里使用-如果传递FileInfo对象,则会自动采用适当的属性(恕我直言,您不应该这样做,因为PowerShell的功能来自传递结构化对象,而不是字符串)。此外,您可以将所有内容放入一个单一的管道中:(((gci $source) -match $filter) | cp -dest $destination为简洁起见,略有改动-随时可以更改;我只是说在foreach那里没有必要)。
乔伊

当我测试它时,我无法正确传送对象。这反过来迫使我使用foreach命令。我将尝试您的代码,看看会发生什么。感谢您指出了这一点。
Doltknuckle

这与我的目标目录变平一样吗?xcopy通常会在目标目录上保留目录结构,对吗?
user33788 2010年

Copy-Item : Cannot bind argument to parameter 'Path' because it is null
伊恩·博伊德

请注意,这Trim并不是要从另一个字符串的末尾删除一个字符串,而是要从调用它的字符串的开头和结尾删除参数字符串中所有字符的实例。在您的情况下,如果$item.Name包含大写字母C,它还将从字符串开头删除驱动器号C。
Andris 2012年

3

PowerShell是完成该任务的出色工具。您可以使用Copy-Item cmdlet进行复制过程。你可以与其他cmdlet复杂的复制命令管道吧,这里是有人确实做到了:)

正则表达式使用System.Text.RegularExpressions命名空间中的.NET RegEx类,这些类上有快速操作方法

PowerShell还具有-match和-replace运算符,可在通过copy-item进行管道传输时使用

还有一些工具可以帮助您创建RegEx本身,例如RegEx好友


恕我直言,-match并且-replace在进入之前应该被提及System.Text.RegularExpressions.RegEx。至少对我来说,我很少[regex]直接使用。然而,我经常使用-match-replace运营商。至于创建正则表达式,我发现PowerShell在测试和完善您正在编写的正则表达式方面也非常有用。
乔伊

我问的答案,你的回答这样一个问题:superuser.com/questions/149808/...
伊恩·博伊德

0

作为一个想法,但需要一些工作

dir -r | ?{$ _ -match'[0-9] {13} \。(gif | jpg | png)'} | %{xcopy $ _。fullname c:\ temp}

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.