我正在尝试使用copy-item
复制文件。具体来说,我想将文件夹或其子文件夹中具有特定扩展名的文件复制到另一个位置,并保留子文件夹层次结构。我尝试使用-filter
和-include
指定文件扩展名,但没有复制文件。
我的源和目标路径存储在变量$packageSourcePath
和$objPath
中。当被召唤时,$packageSourcePath
将像下面的".\src\projects\Project1\PackageFiles"
和$objPath
将像下面的".\bld\Project1\obj"
。
我尝试使用的命令是这样的:
Copy-Item -Path $packageSourcePath\* -Filter *.resw -Destination $objPath -Recurse
我也尝试过各种变体,例如从路径中取消*,或者使用-Include而不是-Filter。什么都行不通。如果我省略-Filter参数,则文件复制,但所有文件都被复制。我只想要具有特定扩展名的文件。
我放弃了Copy-Item。 JohnLBevan的答案实际上没有按照我想要的那样做,因为源根目录中的所有文件都被复制,即使它们与过滤器不匹配。我尝试过使用Convert-Path | Select-String | Copy-Item但仍然复制了源根目录中的所有文件。
在不同背景下的联系人提供了一些建议:
1)
Get-ChildItem -Force -Recurse -ErrorAction Ignore -Path $ packageSourcePath -Filter * .resw | %{ $ src = $ _。FullName $ dst = Join-Path $ objPath $ src.SubString($ packageSourcePath.Length) echo“copy”“$ src”“”“$ dst”“” }
我认为这有点难以理解,因此对于下一个人(可能是像我这样的另一个PS新手)来说,从现在起一年后就难以维持。 (“为什么这里需要-ErrorAction参数?Substring()方法的行为是什么,为什么我不能使用Get-Help找到它?”)
在重新熟悉attrib并检查xcopy开关的效果之后,这个建议更加清晰:
2)
cd $ packageSourcePath attrib -a / s attrib + a * .resw / s xcopy / eidlm $ packageSourcePath $ objPath
但是如果我们要使用xcopy,我们不需要调用attrib:
xcopy $ packageSourcePath * .resw $ objPath / s / i> $ null
对于我的场景,唯一的问题是如果找不到匹配的文件,xcopy会发出错误。我的脚本用于VSTS构建任务,xcopy错误导致构建任务失败。 (因为这个原因,我猜这个建议2对我来说也不行。)
所以,我选择了这个:
# In PS version 5.1, nothing gets copied using Copy-Item $packageSourcePath\* -Filter *.resw ... # so resorting to using xcopy, which mostly works. The one issue is that xcopy will output an # error if no matching file is found, so using GCI first to test for a matching file. if ($(Get-ChildItem $packageSourcePath\*.resw -Recurse).count -gt 0) { xcopy $packageSourcePath\*.resw $objPath /s /i > $null }
添加使用GCI的条件以在调用xcopy之前检查是否存在匹配文件,从而避免任何错误。
我仍然惊讶于Copy-Item -Filter -Recurse不起作用。
这应该这样做(显然这可以在一行中完成;我已经为变量赋值,只是为了让它可读/不言自明):
[string]$filter = '*.resw'
[string]$source = Join-Path -Path $packageSourcePath -ChildPath '*'
[string]$target = $objPath
$source | Convert-Path | Copy-Item -Filter $filter -Recurse -Destination $target -Container #-Force
笔记:
c:\temp\from
复制到c:\temp\to
,我们不想要c:\temp\to\from
(除非它是c:\temp\from\from
的副本))。Join-Path
cmdlet附加此星号以确保将适当的斜杠插入到路径中。Convert-Path
来解析子文件夹/文件名的星号...由于某种原因,copy-item
不能很好地处理这些星号。注意:Convert-Path
可能会返回一系列路径;即如果源文件夹下直接有多个文件/子文件夹。 Get-Item
或Resolve-Path
同样可以用于此;我更喜欢Convert-Path
,因为它返回一个简单的字符串数组,而不是更复杂的类型;但是使用任何一个都没有强烈的争论。Copy-Item
命令,以便它可以应用于Convert-Path
返回的每个路径。-Recurse
说我们对复制路径的子文件夹中的任何内容感兴趣。-Container
参数,表示我们希望在复制时保留任何文件夹结构。严格来说这不是必需的,因为这个开关默认为true(即我们应该指定我们是否不想要这种行为:-Container:$false
;但我想清楚我故意想保留目录结构,而不是离开假设我可能没有想到这一点。这里有更好的解释:https://stackoverflow.com/a/21798660/361842。-Force
;这意味着如果目标中已存在同名项目,我们会覆盖它而不是出错。相关文档:
根据评论,此解决方案应确保只复制您想要的项目,并且预先存在的目录不应导致问题。
[string]$filter = '*.resw'
[string]$source = $packageSourcePath
[string]$target = $objPath
#copy all files in subfolders of the source
$source | Get-ChildItem -Directory | Copy-Item -Filter $filter -Recurse -Destination $target -Container -Force
#copy all files in root of the source
$source | Get-ChildItem -File -Filter $filter | Copy-Item -Destination $target -Container -Force
该解决方案使用2个步骤;可能有更好的选择,但由于这个cmdlet中的特性/ bug,上面是一个可靠的选择。