1

У меня есть папка с подпапками фотографий в формате 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

так далее... Опять есть несколько сотен этих папок.

Что я хочу сделать, это скопировать файлы из 'masters'tree в новую папку ТОЛЬКО, если такое же имя файла существует в дереве' jpgs '. Не все файлы в дереве мастеров имеют соответствующий jpg - эти файлы будут игнорироваться.

Надеюсь, я объяснил это ясно ... какие-нибудь указатели?

2 ответа2

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 это псевдоним для 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 является регулярным выражением, в котором обратная косая черта - это специальный символ, который необходимо экранировать, тогда как обратная косая черта не является специальным символом в строке замены (второй параметр).

2
$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

    }
}

Всё ещё ищете ответ? Посмотрите другие вопросы с метками .