如何在PowerShell 7.x中按含路径的通配符列表复制文件及目录
在PowerShell 7.x实现类似rsync的路径筛选复制
要实现你需要的「按部分路径(含通配符、文件/文件夹)筛选源目录,复制到目标目录并保留结构」的功能,Copy-Item的-Include/-Filter确实不好用——它们只对最后一级文件名/文件夹名生效,没法匹配完整相对路径。下面给你两种可行的实现方式:
方法1:原生PowerShell cmdlet实现
先定义好源目录、目标目录和要筛选的路径模式:
$sourceDir = "/path/to/source" $destDir = "/path/to/destination" # 模式和bash脚本一致,支持通配符* $includePatterns = @( "CMake/somefilepattern*", "include/somefile.h", "source/somefolder/*" )
然后遍历源目录所有文件,筛选符合模式的项并复制:
# 处理文件复制,保留目录结构 Get-ChildItem -Path $sourceDir -Recurse -File | ForEach-Object { # 获取文件相对于源目录的路径 $relativePath = $_.FullName.Substring($sourceDir.Length + 1) # 检查是否匹配任意指定模式 foreach ($pattern in $includePatterns) { if ($relativePath -like $pattern) { # 构建目标文件路径 $destFilePath = Join-Path $destDir $relativePath # 先创建目标文件夹(不存在则自动创建) New-Item -ItemType Directory -Path (Split-Path $destFilePath -Parent) -Force | Out-Null # 复制文件 Copy-Item -Path $_.FullName -Destination $destFilePath -Force break } } } # 处理空文件夹:如果模式包含带/*的文件夹,确保空文件夹也被复制 foreach ($pattern in $includePatterns) { if ($pattern.EndsWith("/*")) { $folderPath = $pattern.Substring(0, $pattern.Length - 2) $sourceFolder = Join-Path $sourceDir $folderPath if (Test-Path $sourceFolder -PathType Container) { $destFolder = Join-Path $destDir $folderPath New-Item -ItemType Directory -Path $destFolder -Force | Out-Null } } }
核心细节
- 相对路径匹配:通过计算文件相对于源目录的路径,才能用
-like匹配你指定的完整模式 - 空文件夹处理:
Get-ChildItem -File不会遍历空文件夹,所以需要单独处理带/*的模式 - 通配符支持:PowerShell的
-like支持*(匹配任意字符)和?(匹配单个字符),和bash通配符逻辑一致
方法2:用Robocopy(更高效)
Robocopy是Windows自带的高效文件复制工具,PowerShell里直接调用即可,它天生支持路径模式筛选,比原生cmdlet快很多,适合大量文件的场景:
$sourceDir = "/path/to/source" $destDir = "/path/to/destination" $includePatterns = @( "CMake\somefilepattern*", "include\somefile.h", "source\somefolder\*" ) # /E:复制所有子目录(含空目录);/MT:启用多线程;/INCLUDE:指定筛选模式 robocopy $sourceDir $destDir /E /MT /INCLUDE:$($includePatterns -join ',')
核心细节
/E参数保证目录结构完整,包括空文件夹/INCLUDE支持多个模式,用逗号分隔即可/MT启用多线程复制,默认8线程,可加数字指定(如/MT:16)- Robocopy路径分隔符用
\更稳妥,PowerShell也能识别/,但避免跨平台问题优先用\
为什么Copy-Item的参数不好用?
Copy-Item的-Include和-Filter只作用于最后一级路径元素,比如你写Copy-Item -Path $sourceDir\* -Include "include/somefile.h" -Recurse,它只会找文件名是include/somefile.h的文件,而不是路径里包含这个字符串的文件——这就是你之前失败的原因。
内容的提问来源于stack exchange,提问作者Richard W
相关产品推荐
相关产品推荐

