Como copiar uma estrutura de diretório, mas incluir apenas alguns arquivos (usando arquivos em lote do Windows)

103

Como o título diz, como posso copiar recursivamente uma estrutura de diretório, mas incluir apenas alguns arquivos. Por exemplo, dada a seguinte estrutura de diretório:

folder1
  folder2
    folder3
      data.zip
      info.txt
      abc.xyz
    folder4
    folder5
      data.zip
      somefile.exe
      someotherfile.dll

Os arquivos data.zip e info.txt podem aparecer em qualquer lugar na estrutura de diretório. Como posso copiar a estrutura de diretório completa, mas incluir apenas arquivos denominados data.zip e info.txt (todos os outros arquivos devem ser ignorados)?

A estrutura de diretório resultante deve ser semelhante a esta:

copy_of_folder1
  folder2
    folder3
      data.zip
      info.txt
    folder4
    folder5
      data.zip
M4N
fonte

Respostas:

169

Você não menciona se tem que ser apenas em lote, mas se você pode usar ROBOCOPY, tente isto:

ROBOCOPY C:\Source C:\Destination data.zip info.txt /E

EDIT: Alterado o /Sparâmetro /Epara incluir pastas vazias.

aforia
fonte
Posso copiar * .zip com esta sintaxe? Tentei escrever apenas * .zip em vez de data.zip, mas não copiou os arquivos, apenas as pastas. Eu também tentei? .Zip
Niels Brinch
@Niels Brinch Sim, você deveria ser capaz de fazer isso. Qual é a linha de comando exata que você está usando?
aphoria
1
ROBOCOPY C: \ Source C: \ Destination * .zip / E
Niels Brinch
Esquisito. Qual sistema operacional você está usando? Você tem as permissões de arquivo / pasta necessárias? Acabei de testar no Win 7 e *.zipfuncionou para mim.
aphoria de
Realmente!? Também estou usando o Win 7. Quando tento, ele simplesmente não copia nenhum arquivo. Apenas pastas. Vou tentar de novo. (Já que estamos nisso, qual é a sintaxe para incluir mais de * .zip - digamos * .zip e * .jpg.
Niels Brinch
29

Uma solução alternativa que copia um arquivo por vez e não requer ROBOCOPY:

@echo off
setlocal enabledelayedexpansion

set "SOURCE_DIR=C:\Source"
set "DEST_DIR=C:\Destination"
set FILENAMES_TO_COPY=data.zip info.txt

for /R "%SOURCE_DIR%" %%F IN (%FILENAMES_TO_COPY%) do (
    if exist "%%F" (
        set FILE_DIR=%%~dpF
        set FILE_INTERMEDIATE_DIR=!FILE_DIR:%SOURCE_DIR%=!
        xcopy /E /I /Y "%%F" "%DEST_DIR%!FILE_INTERMEDIATE_DIR!"
    )
)

A instrução for externa gera qualquer combinação de caminho possível de subdiretório em SOURCE_DIRe nome em FILENAMES_TO_COPY. Para cada arquivo existente, o xcopy é chamado. FILE_INTERMEDIATE_DIRcontém o caminho do subdiretório do arquivo dentro do SOURCE_DIRqual precisa ser criado em DEST_DIR.

sakra
fonte
1
Eu precisava copiar todas as fotos de pastas e subpastas, esse script em lote ajudou. Acabei de alterar a linha set FILENAMES_TO_COPY=data.zip info.txtacima paraset FILENAMES_TO_COPY=*.jpg
Kai Noack
Estou recebendo um erro porque o caminho do arquivo contém espaços (SOURCE_DIR = "C: \ Teste de Origem", DEST_DIR = "C: \ Teste Dest", erro: O teste "" foi inesperado neste momento). Tentei alterar% var% por! Var! em todos os lugares, mas sem sucesso. Alguma pista sobre como resolver isso? Toda a estrutura está repleta de nomes de pastas com espaços.
ricardo.scholz
1
Experimente set "SOURCE_DIR=C:\Origin Test"e set "DEST_DIR=C:\Dest Test". Observe a colocação das aspas duplas.
sakra
13

tente canalizar a saída de find (ou seja, o caminho do arquivo) para cpio

find . -type f -name '*.jpg' | cpio -p -d -v targetdir/

cpio verifica o carimbo de data / hora nos arquivos de destino - portanto, é seguro e rápido.

remova -v para operações mais rápidas, assim que você se acostumar com isso.

Gabe Rainbow
fonte
2
@Christian tem uma dependência do cpio que não faz parte da instalação padrão.
Crashworks de
8

Se o Powershell for uma opção, você pode fazer o seguinte:

Copy-Item c:\sourcePath d:\destinationPath -filter data.zip -recurse

A principal desvantagem é que ele copia todas as pastas, mesmo que fiquem vazias porque nenhum arquivo corresponde ao filtro especificado. Então você pode acabar com uma árvore cheia de pastas vazias, além das poucas pastas que contêm os arquivos que você deseja.

Neil
fonte
Executá-lo uma segunda vez mudará o destino. (Coloca os arquivos em uma subpasta.) É um comportamento bobo, se você me perguntar. Você vai querer correr rm -r -ErrorAction:SilentlyContinue d:\destinationPathantes de copiar para consertar isso.
MakotoE de
7

Graças às respostas anteriores. :)

Este script denominado "r4k4copy.cmd":

@echo off
for %%p in (SOURCE_DIR DEST_DIR FILENAMES_TO_COPY) do set %%p=
cls
echo :: Copy Files Including Folder Tree
echo :: http://stackoverflow.com
rem     /questions/472692/how-to-copy
rem     -a-directory-structure-but-only
rem     -include-certain-files-using-windows
echo :: ReScripted by r4k4
echo.
if "%1"=="" goto :NoParam
if "%2"=="" goto :NoParam
if "%3"=="" goto :NoParam
setlocal enabledelayedexpansion
set SOURCE_DIR=%1
set DEST_DIR=%2
set FILENAMES_TO_COPY=%3
for /R "%SOURCE_DIR%" %%F IN (%FILENAMES_TO_COPY%) do (
if exist "%%F" (
set FILE_DIR=%%~dpF
set FILE_INTERMEDIATE_DIR=!FILE_DIR:%SOURCE_DIR%=!
xcopy /E /I /Y "%%F" "%DEST_DIR%!FILE_INTERMEDIATE_DIR!"
)
)
goto :eof
:NoParam
echo.
echo Syntax: %0 [Source_DIR] [Dest_DIR] [FileName]
echo Eg.   : %0 D:\Root E:\Root\Lev1\Lev2\Lev3 *.JPG
echo Means : Copy *.JPG from D:\Root to E:\Root\Lev1\Lev2\Lev3

Aceita variáveis ​​de "Origem", "Destino" e "Nome do arquivo". Ele também pode copiar apenas tipos específicos de arquivos ou nomes de arquivos seletivos.

Qualquer melhoria é bem-vinda. :)

Rhak Kahr
fonte
5

Com find e cp apenas:

mkdir /tmp/targetdir
cd sourcedir
find . -type f -name '*.zip' -exec cp -p --parents {} /tmp/targetdir ";"
find . -type f -name '*.txt' -exec cp -p --parents {} /tmp/targetdir ";"
Rop
fonte
4

Semelhante à solução de Paulius, mas os arquivos com os quais você não se importa não são copiados e depois excluídos:

@echo OFF

:: Replace c:\temp with the directory where folder1 resides.
cd c:\temp

:: You can make this more generic by passing in args for the source and destination folders.
for /f "usebackq" %%I in (`dir /b /s /a:-d folder1`) do @echo %%~nxI | find /V "data.zip" | find /v "info.txt" >> exclude_list.txt
xcopy folder1 copy_of_folder1 /EXCLUDE:exclude_list.txt /E /I
Patrick Cuff
fonte
4

Para copiar todos os arquivos de texto para G: e preservar a estrutura do diretório:

xcopy *.txt /s G:
Osbert Snudge
fonte
isso pode funcionar recursivamente, como copiar todos os .txt das subpastas e preservar a estrutura do diretório em relação ao diretório base?
Micka
3

São apenas dois comandos simples, mas eu não recomendaria isso, a menos que os arquivos que você NÃO precisa copiar sejam pequenos. Isso porque isso copiará TODOS os arquivos e, em seguida, removerá os arquivos desnecessários da cópia.

xcopy /E /I folder1 copy_of_folder1
for /F "tokens=1 delims=" %i in ('dir /B /S /A:-D copy_of_files ^| find /V "info.txt" ^| find /V "data.zip"') do del /Q "%i"

Claro, o segundo comando é meio longo, mas funciona!

Além disso, essa abordagem não exige que você baixe e instale nenhuma ferramenta de terceiros (o Windows 2000+ BATCH tem comandos suficientes para isso).

Paulius
fonte
Muito obrigado. Como você mencionou, não é o ideal, porque (no meu caso) os arquivos que devem ser copiados são geralmente pequenos, enquanto os arquivos que não devem ser copiados são maiores (e pode haver muitos deles).
M4N
2

No Linux e em outros sistemas UNIX, usar o tarcomando faria isso facilmente.

$ tar cvf /tmp/full-structure.tar *data.zip *info.txt

Então você mudaria para o alvo e:

$ tar xvf /tmp/full-structure.tar 

É claro que você pode canalizar a saída do primeiro alcatrão para o segundo, mas vê-lo funcionar em etapas é mais fácil de entender e explicar. Estou faltando o cd / para / novo / caminho / necessário no comando a seguir - só não me lembro como fazer isso agora. Alguém pode adicioná-lo, espero.

$ tar cvf -  *data.zip *info.txt |  tar xvf - 

Tar (gnutar) também está disponível no Windows, mas provavelmente eu mesmo usaria o xcopymétodo nessa plataforma.

JohnP
fonte
tar cvf /tmp/full-structure.tar ** / data.zip ** / info.txt funcionou para mim
ssinganamalla
Ambos "tar cvf /tmp/full-structure.tar ** / data.zip ** / info.txt" e "tar cvf /tmp/full-structure.tar * data.zip * info.txt" me deram 3 erros : (1) "tar: * data.zip: Impossível stat: Nenhum arquivo ou diretório", (2) "tar * info.txt: Impossível stat: Nenhum arquivo ou diretório", (3) "tar: Saindo com status de falha devido a erros anteriores ". De qual pasta eu faço tudo isso? Eu não entendo esse método.
user1271772
A pergunta diz WINDOWS
Anfelipe
Win10 tem WSL, o que o torna válido. O tar está disponível no Windows há mais de 20 anos e o uso de um pipe tem funcionado desde os dias do MS-DOS. Em qualquer ambiente de shell, o PWD é importante. PWD - atual diretório de trabalho. Admito que esta solução é menos para usuários finais e mais para usuários avançados ou programadores.
JohnP
1
XCOPY /S folder1\data.zip copy_of_folder1  
XCOPY /S folder1\info.txt copy_of_folder1

EDITAR: Se você quiser preservar as pastas vazias (que, ao reler sua postagem, você parece) use / E em vez de / S.

gkrogers
fonte
1
não preserva a estrutura de pastas.
Paulius
A opção / E preserva a estrutura da pasta, incluindo a criação de pastas vazias, se necessário. O nome do arquivo também funciona com um caractere curinga (por exemplo, pasta1 \ *. Zip). Só recebo o "Erro de arquivo não encontrado" quando passo um nome de arquivo completo que não existe (nesse caso, recebo "Arquivo não encontrado - xxx.xxx 0 Arquivo (s) copiado (s)". Quando dou um padrão que não retorna nenhum arquivo (por exemplo, pasta1 \ *. zzz), eu apenas recebo "0 Arquivo (* s) copiado".
gkrogers
1

Usando a interface de linha de comando WinRAR, você pode copiar os nomes de arquivo e / ou tipos de arquivo para um arquivo. Em seguida, você pode extrair esse arquivo para qualquer local que desejar. Isso preserva a estrutura do arquivo original.

Eu precisava adicionar arquivos de imagens de álbuns perdidos ao meu celular, sem ter que copiar a música novamente. Felizmente, a estrutura de diretórios era a mesma no meu computador e no meu celular!

Eu usei:

   rar a -r C:\Downloads\music.rar X:\music\Folder.jpg
  • C: \ Downloads \ music.rar = Arquivo a ser criado
  • X: \ music \ = Pasta contendo arquivos de música
  • Folder.jpg = Nome do arquivo que eu queria copiar

Isso criou um arquivo com todos os arquivos Folder.jpg nos subdiretórios apropriados.

Essa técnica também pode ser usada para copiar tipos de arquivo. Se todos os arquivos tivessem nomes diferentes, você poderia escolher extrair todos os arquivos para um único diretório. Parâmetros de linha de comando adicionais podem arquivar vários tipos de arquivo.

Mais informações neste link muito útil http://cects.com/using-the-winrar-command-line-tools-in-windows/

Jim_Joat
fonte
1

Para quem usa Altap Salamander (gerenciador de arquivos de 2 painéis): no pop-up Opções de Cópia, basta especificar os nomes dos arquivos ou máscaras. Fácil.

Hugo P
fonte
0

Eu estou bem com expressões regulares, preguiçosas e avessas a instalações, então criei um arquivo em lote que cria o diretório e copia com comandos do DOS vanilla. Parece trabalhoso, mas mais rápido para mim do que fazer robocópia.

  1. Crie sua lista de arquivos de origem com caminhos completos, incluindo a letra da unidade, se necessário, em um arquivo de texto.
  2. Ative as expressões regulares em seu editor de texto.
  3. Adicione aspas em volta de cada linha em caso de espaços - string de pesquisa (.*)substitua a string "\1"e clique em substituir tudo
  4. Crie duas linhas por arquivo - uma para criar o diretório, outra para copiar o arquivo (qqq será substituído pelo caminho de destino) - string de pesquisa (.*)substituir string md qqq\1\nxcopy \1 qqq\1\ne clicar em substituir tudo
  5. Remova o nome do arquivo dos caminhos de destino - pesquise \\([^\\^"]+)"\n substituir\\"\n
  6. Substitua no caminho de destino (neste exemplo A:\srce B:\dest). DESLIGUE as expressões regulares, pesquise qqq"A:\src\substituir B:\dest\e clique em substituir tudo.

md criará diretórios aninhados. copy provavelmente se comportaria de forma idêntica a xcopy neste exemplo. Você pode querer adicionar / Y ao xcopy para suprimir as confirmações de substituição. Você acaba com um arquivo em lote assim:

md "B:\dest\a\b\c\"
xcopy "C:\src\a\b\c\e.xyz" "B:\dest\a\b\c\e.xyz"

repetido para cada arquivo em sua lista original. Testado em Win7.

Chris
fonte
-1

Para fazer isso com arrastar e soltar, use o winzip, há uma opção de preservação da estrutura dir. Basta criar um novo .zip no nível do diretório que será sua raiz e arrastar os arquivos para dentro.

Gnoy Dav
fonte
Obrigado, mas estava procurando uma solução para ser usada a partir de arquivos de script (lote). Então, sem arrastar e soltar ...
M4N