我有一个文件夹,里面有 jpg 格式的照片子文件夹。文件排列如下:
Z:\jpgs\Armouries\fb\IMG_1286.jpg
Z:\jpgs\Balloon\fb\IMG_1129.jpg
Z:\jpgs\Party\fb\P5060092.jpg
等等...这样的有几百个。
我还有另一个文件夹,其中包含以下子文件夹:
z:\masters\Armouries\IMG_1286.RAW
z:\masters\Balloon\IMG_1129.DNG
z:\masters\Party\P5060092.CR2
等等... 又有数百个这样的文件夹。
我想要做的是,仅当“jpgs”树中存在相同文件名时,才将“masters”树中的文件复制到新文件夹。 masters 树中的所有文件并非都有相应的 jpg - 这些文件将被忽略。
希望我已经解释清楚了...有什么指点吗?
答案1
$jpgs = "C:\jpgs"
$masters = "C:\masters"
$destination = "C:\new"
# store all BaseNames and necessary parent folders to match in an array
$namesToMatch = @()
gci $jpgs -File -Recurse | select -ExpandProperty FullName -Uniq | % {
# BaseName and parent folder(s) (eg "\Armouries\IMG_1286")
$namesToMatch += (($_ -split "\\jpgs")[-1] -split "\.")[0]
}
# evaluate each file we might need to copy
gci $masters -File -Recurse | select -ExpandProperty FullName -Uniq | % {
# BaseName and parent folder(s) (eg "\Armouries\IMG_1286")
$name = (($_ -split "\\masters")[-1] -split "\.")[0]
# path + Fullname, in the "new" folder structure (eg "C:\new\Armouries\IMG_1286.jpg")
$desiredDestination = $_ -replace "masters","new"
# path in the "new" folder structure with no file name (eg "C:\new\Armouries")
$desiredDestination_noFile = $desiredDestination.Substring(0,$desiredDestination.LastIndexOf("\"))
# if we should copy this file
if($name -in $namesToMatch) {
# create the parent directories if needed
if(!(Test-Path -Path $desiredDestination_noFile)) {
md -force $desiredDestination_noFile | Out-File null
}
# copy the file
cp $_ $desiredDestination
}
}
答案2
此答案假设与问题中的约定相同,即母版在 中z:\masters
,JPG 在 中z:\jpgs
。目标文件夹假定为z:\dest
。
简短回答
dir -File -Recurse z:\masters\ | % { if (dir -Recurse "z:\jpgs\$($_.BaseName).jpg") { mkdir -ErrorAction SilentlyContinue $($_.Directory -replace "\\masters\\", "\dest\"); cp $_.FullName $($_.FullName -replace "\\masters\\", "\dest\")} }
简要说明:对于z:\masters
其直接或间接子目录中的每个文件或其直接或间接子目录之一,它会检查任何直接或间接子目录是否z:\jpgs
包含具有相同基本名称的 JPG 文件,如果是,则在必要时创建父目录后将主文件复制到目标文件夹。
您可以测试此解决方案在线。(注:在线版本使用/
而不是 作为路径分隔符,\
因为它运行在 Linux 上,而New-Item -Type Directory
而不是mkdir
由于在线执行环境的限制。)
使用适当的缩进和扩展别名
Get-ChildItem -File -Recurse z:\masters\ | ForEach-Object {
if (Get-ChildItem -Recurse "z:\jpgs\$($_.BaseName).jpg") {
mkdir -ErrorAction SilentlyContinue $($_.Directory -replace "\\masters\\", "\dest\")
Copy-Item $_.FullName $($_.FullName -replace "\\masters\\", "\dest\")
}
}
详细说明
dir -File -Recurse z:\masters\
列出z:\masters
及其子目录中的所有文件 (-Recurse
)。dir
是获取子项%
是ForEach 对象{}
. 它为管道中的每个对象执行一个脚本块(用括号括起来)。$_
是个管道中的当前对象(即主文件之一)。dir -Recurse "z:\jpgs\$($_.BaseName).jpg"
返回z:\jpgs
目录及其子目录中所有与当前主文件具有相同基本名称 ($_.BaseName
) 和扩展名的文件。如果没有,则.jpg
返回,然后在评估语句的条件时将其转换为。$null
$false
if
$_.FullName -replace "\\masters\\", "\dest\"
是目标文件的完整路径:它是主文件的完整路径($_.FullName
),\masters\
其中\dest\
使用-replace 运算符。这用于具有与 中相同的目录\dest
结构\masters
。mkdir -ErrorAction SilentlyContinue $($_.Directory -replace "\\masters\\", "\dest\")
创建目标文件的父文件夹。此步骤是必需的,因为Copy-Item
目前不允许(自 PowerShell 6.1 起)在必要时创建父目录,如果父目录缺失,则命令会失败。如果父目录已存在,则该-ErrorAction SilentlyContinue
参数可防止mkdir
命令失败。Copy-Item $_.FullName $($_.FullName -replace "\\masters\\", "\dest\")
将主文件复制到目标文件夹。
评论
在$_.FullName -replace "\\masters\\", "\dest\"
表达式中,\
第一个参数中的反斜杠 ( ) 是双倍的,-replace
但第二个参数中的反斜杠不是双倍的。这是因为-replace 运算符是正则表达式其中反斜杠是需要转义的特殊字符,而反斜杠不是替换字符串(第二个参数)中的特殊字符。