Cómo copiar una estructura de directorio pero solo incluir ciertos archivos (usando archivos por lotes de Windows)

103

Como dice el título, ¿cómo puedo copiar recursivamente una estructura de directorio pero solo incluir algunos archivos? Por ejemplo, dada la siguiente estructura de directorios:

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

Los archivos data.zip e info.txt pueden aparecer en cualquier parte de la estructura del directorio. ¿Cómo puedo copiar la estructura completa del directorio, pero solo incluir archivos llamados data.zip e info.txt (todos los demás archivos deben ignorarse)?

La estructura de directorio resultante debería verse así:

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

Respuestas:

169

No menciona si tiene que ser solo por lotes, pero si puede usarlo ROBOCOPY, intente esto:

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

EDITAR: Se modificó el /Sparámetro /Epara incluir carpetas vacías.

aforia
fuente
¿Puedo copiar * .zip con esta sintaxis? Intenté simplemente escribir * .zip en lugar de data.zip, pero no copió los archivos, solo las carpetas. También probé? .Zip
Niels Brinch
@Niels Brinch Sí, deberías poder hacer eso. ¿Cuál es la línea de comando exacta que estás usando?
aphoria
1
ROBOCOPÍA C: \ Fuente C: \ Destino * .zip / E
Niels Brinch
Extraño. ¿Qué sistema operativo estás usando? ¿Tiene los permisos de archivo / carpeta necesarios? Probé en Win 7 y *.ziptrabajé para mí.
aphoria
¿¡De Verdad!? También estoy usando Win 7. Cuando lo intento, simplemente no copia ningún archivo. Solo carpetas. Intentaré de nuevo. (Ya que estamos en eso, ¿cuál es la sintaxis para incluir más de * .zip, digamos * .zip y * .jpg.
Niels Brinch
29

Una solución alternativa que copia un archivo a la vez y no requiere ROBOCOPIA:

@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!"
    )
)

La instrucción for externa genera cualquier combinación de ruta posible de subdirectorio en SOURCE_DIRy nombre en FILENAMES_TO_COPY. Para cada archivo existente se invoca xcopy. FILE_INTERMEDIATE_DIRcontiene la ruta del subdirectorio del archivo dentro del SOURCE_DIRcual debe crearse DEST_DIR.

sakra
fuente
1
Necesitaba copiar todas las fotos de carpetas y subcarpetas, este script por lotes me ayudó. Acabo de cambiar la línea de set FILENAMES_TO_COPY=data.zip info.txtarriba aset FILENAMES_TO_COPY=*.jpg
Kai Noack
Recibo un error porque la ruta del archivo tiene espacios (SOURCE_DIR = "C: \ Origin Test", DEST_DIR = "C: \ Dest Test", error: Test "" fue inesperado en este momento). Intenté cambiar% var% por! Var! en todas partes, pero sin éxito. ¿Alguna pista sobre cómo solucionar esto? Toda la estructura está llena de nombres de carpetas con espacios.
ricardo.scholz
1
Prueba set "SOURCE_DIR=C:\Origin Test"y set "DEST_DIR=C:\Dest Test". Tenga en cuenta la ubicación de las comillas dobles.
sakra
13

intente canalizar la salida de buscar (es decir, la ruta del archivo) en cpio

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

cpio verifica la marca de tiempo en los archivos de destino, por lo que es seguro y rápido.

elimine -v para una operación más rápida, una vez que se acostumbre.

Arcoiris de gabe
fuente
2
@Christian tiene una dependencia de cpio que no es parte de la instalación estándar.
Crashworks
8

Si Powershell es una opción, puede hacer esto:

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

La principal desventaja es que copia todas las carpetas, incluso si terminan vacías porque ningún archivo coincide con el filtro que especifica. Por lo tanto, podría terminar con un árbol lleno de carpetas vacías, además de las pocas carpetas que tienen los archivos que desea.

Neil
fuente
Ejecutar esto por segunda vez cambiará el destino. (Coloca los archivos en una subcarpeta). Es un comportamiento tonto si me preguntas. Querrá ejecutar rm -r -ErrorAction:SilentlyContinue d:\destinationPathantes de copiar para solucionarlo.
MakotoE
7

Gracias a las respuestas anteriores. :)

Este script llamado "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

Acepta variables de "Origen", "Destino" y "Nombre de archivo". También puede copiar solo tipos específicos de archivos o nombres de archivos selectivos.

Cualquier mejora es bienvenida. :)

Rhak Kahr
fuente
5

Solo con buscar y cp:

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
fuente
4

Similar a la solución de Paulius, pero los archivos que no le importan no se copian y luego se eliminan:

@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
fuente
4

Para copiar todos los archivos de texto a G: y preservar la estructura del directorio:

xcopy *.txt /s G:
Osbert Snudge
fuente
¿Puede esto funcionar de forma recursiva, como copiar todo .txt de subcarpetas y preservar la estructura del directorio en relación con el directorio base?
Micka
3

Son solo dos comandos simples, pero no lo recomendaría, a menos que los archivos que NO necesita copiar sean pequeños. Esto se debe a que esto copiará TODOS los archivos y luego eliminará los archivos que no se necesitan en la copia.

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, el segundo comando es un poco largo, ¡pero funciona!

Además, este enfoque no requiere que descargue e instale ninguna herramienta de terceros (Windows 2000+ BATCH tiene suficientes comandos para esto).

Paulius
fuente
Muchas gracias. Como mencionaste, no es lo ideal, porque (en mi caso) los archivos que se deben copiar suelen ser pequeños, mientras que los archivos que no se deben copiar son más grandes (y puede haber muchos).
M4N
2

En Linux y otros sistemas UNIX, usar el tarcomando haría esto fácilmente.

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

Entonces cwd al objetivo y:

$ tar xvf /tmp/full-structure.tar 

Por supuesto, podría canalizar la salida del primer alquitrán al segundo, pero verlo funcionar en pasos es más fácil de entender y explicar. Me falta el cd / to / new / path / necesario en el siguiente comando; simplemente no recuerdo cómo hacerlo ahora. Alguien más puede agregarlo, con suerte.

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

Tar (gnutar) también está disponible en Windows, pero probablemente usaría el xcopymétodo yo mismo en esa plataforma.

JohnP
fuente
tar cvf /tmp/full-structure.tar ** / data.zip ** / info.txt funcionó para mí
ssinganamalla
Tanto "tar cvf /tmp/full-structure.tar ** / data.zip ** / info.txt" y "tar cvf /tmp/full-structure.tar * data.zip * info.txt" me dieron 3 errores : (1) "tar: * data.zip: No se puede establecer: No existe tal archivo o directorio", (2) "tar * info.txt: No se puede estad: No se existe tal archivo o directorio", (3) "tar: Saliendo con estado de falla debido a errores anteriores ". ¿Desde qué carpeta hago todo esto? No entiendo este método.
user1271772
La pregunta dice WINDOWS
Anfelipe
Win10 tiene WSL, lo que hace que esto sea válido. tar ha estado disponible en Windows durante más de 20 años y el uso de una tubería ha funcionado desde los días de MS-DOS. En cualquier entorno de shell, el PWD es importante. PWD: directorio de trabajo actual. Admito que esta solución es menos para usuarios finales y más para usuarios avanzados o programadores.
JohnP
1
XCOPY /S folder1\data.zip copy_of_folder1  
XCOPY /S folder1\info.txt copy_of_folder1

EDITAR: Si desea conservar las carpetas vacías (que, al releer su publicación, parece que lo hace) use / E en lugar de / S.

gkrogers
fuente
1
no conserva la estructura de la carpeta.
Paulius
La opción / E conserva la estructura de la carpeta, incluida la creación de carpetas vacías si es necesario. El nombre de archivo también funciona con un comodín (por ejemplo, carpeta1 \ *. Zip). Solo obtengo el "Error de archivo no encontrado" cuando le paso un nombre de archivo completo que no existe (en cuyo caso obtengo "Archivo no encontrado - xxx.xxx 0 Archivo (s) copiado". Cuando le doy un patrón que no devuelve archivos (por ejemplo, carpeta1 \ *. zzz), solo obtengo "0 Archivo (* s) copiado".
gkrogers
1

Usando la interfaz de línea de comandos de WinRAR, puede copiar los nombres de archivo y / o tipos de archivo a un archivo. Luego, puede extraer ese archivo a la ubicación que desee. Esto conserva la estructura del archivo original.

Necesitaba agregar archivos de imágenes de álbumes faltantes a mi teléfono móvil sin tener que volver a copiar la música. ¡Afortunadamente, la estructura del directorio era la misma en mi computadora y en mi móvil!

Solía:

   rar a -r C:\Downloads\music.rar X:\music\Folder.jpg
  • C: \ Downloads \ music.rar = Archivo a crear
  • X: \ music \ = Carpeta que contiene archivos de música
  • Folder.jpg = Nombre de archivo que quería copiar

Esto creó un archivo con todos los archivos Folder.jpg en los subdirectorios adecuados.

Esta técnica también se puede utilizar para copiar tipos de archivos. Si todos los archivos tienen nombres diferentes, puede optar por extraer todos los archivos en un solo directorio. Los parámetros adicionales de la línea de comandos pueden archivar varios tipos de archivos.

Más información en este enlace muy útil http://cects.com/using-the-winrar-command-line-tools-in-windows/

Jim_Joat
fuente
1

Para aquellos que usan Altap Salamander (administrador de archivos de 2 paneles): en las Opciones de la ventana emergente Copiar, simplemente especifique los nombres de archivo o máscaras. Fácil.

Hugo P
fuente
0

Estoy bien con las expresiones regulares, perezoso y reacio a las instalaciones, así que creé un archivo por lotes que crea el directorio y copia con comandos básicos de DOS. Parece laborioso pero más rápido para mí que trabajar con robocopias.

  1. Cree su lista de archivos de origen con rutas completas, incluida la letra de la unidad si es necesario, en un archivo de texto.
  2. Active las expresiones regulares en su editor de texto.
  3. Agregue comillas dobles alrededor de cada línea en caso de espacios - cadena de búsqueda (.*)reemplazar cadena"\1" y haga clic en reemplazar todo
  4. Cree dos líneas por archivo: una para crear el directorio, otra para copiar el archivo (qqq se reemplazará con la ruta de destino); busque la cadena, (.*)reemplace la cadena md qqq\1\nxcopy \1 qqq\1\ny haga clic en reemplazar todo
  5. Eliminar el nombre de archivo de las rutas de destino - buscar \\([^\\^"]+)"\nreemplazar\\"\n
  6. Reemplazar en la ruta de destino (en este ejemplo A:\srcy B:\dest). Desactive las expresiones regulares, busque qqq"A:\src\reemplazar B:\dest\y haga clic en reemplazar todo.

md creará directorios anidados. copy probablemente se comportaría de manera idéntica a xcopy en este ejemplo. Es posible que desee agregar / Y a xcopy para suprimir las confirmaciones de sobrescritura. Terminas con un archivo por lotes como este:

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

repetido para cada archivo en su lista original. Probado en Win7.

Chris
fuente
-1

Para hacer esto con arrastrar y soltar, use winzip, hay una opción de conservación de estructura de directorio. Simplemente cree un nuevo .zip en el nivel del directorio que será su raíz y arrastre los archivos.

Gnoy Dav
fuente
Gracias, pero estaba buscando una solución para usar desde archivos de script (por lotes). Entonces, no arrastrar y soltar ...
M4N