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).