Этот ответ предполагает те же соглашения, что и в вопросе, то есть мастера находятся в 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
это псевдоним для Get-ChildItem
%
является псевдонимом ForEach-Object. Он выполняет блок скрипта (заключенный в фигурные скобки {}
) для каждого объекта в конвейере.
$_
- текущий объект в конвейере (т. е. один из основных файлов).
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 является регулярным выражением, в котором обратная косая черта - это специальный символ, который необходимо экранировать, тогда как обратная косая черта не является специальным символом в строке замены (второй параметр).