Windows - copiando arquivos com base na existência de outros arquivos

1

Eu tenho uma pasta com subpastas de fotos em formato jpg. Os arquivos são organizados da seguinte forma:

Z:\jpgs\Armouries\fb\IMG_1286.jpg
Z:\jpgs\Balloon\fb\IMG_1129.jpg
Z:\jpgs\Party\fb\P5060092.jpg

etc ... Existem algumas centenas delas.

Eu também tenho outra pasta com subpastas da seguinte forma:

z:\masters\Armouries\IMG_1286.RAW
z:\masters\Balloon\IMG_1129.DNG
z:\masters\Party\P5060092.CR2

etc ... Novamente, existem várias centenas dessas pastas.

O que eu quero fazer é copiar os arquivos da árvore 'masters' para uma nova pasta SOMENTE se o mesmo nome de arquivo existir na árvore 'jpgs'. Nem todos os arquivos na árvore mestra têm um jpg correspondente - esses arquivos seriam ignorados.

Espero ter explicado isso claramente ... alguma indicação?

    
por LostPlot 04.09.2018 / 18:34

2 respostas

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

    }
}
    
por 05.09.2018 / 15:57
2

Essa resposta assume as mesmas convenções da pergunta, ou seja, os mestres estão em z:\masters e os JPGs estão em z:\jpgs . A pasta de destino é assumida como z:\dest .

Resposta curta

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\")} }

Breve explicação: para cada arquivo em z:\masters ou um de seus subdiretórios diretos e indiretos, ele verifica se algum subdiretório direto ou indireto de z:\jpgs contém um arquivo JPG com o mesmo nome base e, em caso afirmativo, copia o mestre arquivo para a pasta de destino depois de criar os diretórios pai, se necessário.

Você pode testar esta solução on-line . (Nota: a versão online usa / como o separador de caminho em vez de \ porque é executado no Linux e New-Item -Type Directory em vez de mkdir devido a uma limitação do ambiente de execução on-line.)

Com recuo e aliases adequados expandidos

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\")
    }
}

Explicação detalhada

  • dir -File -Recurse z:\masters\ lista todos os arquivos em z:\masters e seus subdiretórios ( -Recurse ). dir é um alias para Get-ChildItem
  • % é um alias para ForEach-Object . Ele executa um bloco de script (entre chaves {} ) para cada objeto no pipeline.
  • $_ é o objeto atual no pipeline (ou seja, um dos arquivos principais).
  • dir -Recurse "z:\jpgs\$($_.BaseName).jpg" retorna todos os arquivos no diretório z:\jpgs e seus subdiretórios que possuem o mesmo nome base do arquivo mestre atual ( $_.BaseName ) e uma extensão .jpg . Ele retorna $null se não houver nenhum, que é então convertido para $false quando é avaliado como a condição da instrução if .
  • $_.FullName -replace "\masters\", "\dest\" é o caminho completo do arquivo de destino: é o caminho completo do arquivo mestre ( $_.FullName ), em que \masters\ é substituído por \dest\ usando os -replace operator . Isso é usado para ter a mesma estrutura de diretório em \dest como em \masters .
  • mkdir -ErrorAction SilentlyContinue $($_.Directory -replace "\masters\", "\dest\") cria as pastas pai do arquivo de destino. Esta etapa é necessária porque o Copy-Item atualmente não permite (a partir do PowerShell 6.1) criar diretórios pai, se necessário, e falhar quando eles estiverem ausentes. O parâmetro -ErrorAction SilentlyContinue impede que o comando mkdir falhe se os diretórios pai já existirem.
  • Copy-Item $_.FullName $($_.FullName -replace "\masters\", "\dest\") copia o arquivo mestre para a pasta de destino.

Observações

Na expressão $_.FullName -replace "\masters\", "\dest\" , barras invertidas ( \ ) são duplicadas no primeiro parâmetro para -replace , mas não no segundo. Isso ocorre porque o primeiro parâmetro para o operador de substituição é uma expressão regular na qual uma folga é um caractere especial que precisa ser escapado, enquanto que a barra invertida não é um caractere especial na sequência de substituição (o segundo parâmetro).

    
por 17.09.2018 / 15:51