web-dev-qa-db-fra.com

Comment copier une structure de répertoire mais inclure uniquement certains fichiers (en utilisant des fichiers batch Windows)

Comme le titre le dit, comment puis-je copier récursivement une structure de répertoires en n'incluant que certains fichiers? E.g étant donné la structure de répertoire suivante:

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

Les fichiers data.Zip et info.txt peuvent apparaître partout dans la structure de répertoires. Comment puis-je copier la structure de répertoires complète, mais inclure uniquement les fichiers nommés data.Zip et info.txt (tous les autres fichiers doivent être ignorés)?

La structure de répertoire résultante devrait ressembler à ceci:

copy_of_folder1
  folder2
    folder3
      data.Zip
      info.txt
    folder4
    folder5
      data.Zip
91
M4N

Vous ne mentionnez pas s'il doit s'agir uniquement d'un lot, mais si vous pouvez utiliser ROBOCOPY, essayez ceci:

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

EDIT: Changé le /S paramètre sur /E pour inclure des dossiers vides.

148
aphoria

Une solution alternative qui copie un fichier à la fois et ne nécessite pas 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!"
    )
)

L'instruction externe for génère toute combinaison de chemin possible du sous-répertoire dans SOURCE_DIR et nom en FILENAMES_TO_COPY. Pour chaque fichier existant, xcopy est appelé. FILE_INTERMEDIATE_DIR contient le chemin du sous-répertoire du fichier dans SOURCE_DIR qui doit être créé dans DEST_DIR.

29
sakra

essayez la sortie de piping de find (c'est-à-dire le chemin du fichier) dans cpio

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

cpio vérifie l’horodatage des fichiers cibles - il est donc sûr et rapide.

retirez -v pour un fonctionnement plus rapide, une fois que vous vous y serez habitué.

13
Gabe Rainbow

Si Powershell est une option, vous pouvez le faire:

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

Le principal inconvénient est qu'il copie tous les dossiers, même s'ils finiront par être vides, car aucun fichier ne correspond au filtre que vous spécifiez. Ainsi, vous pourriez vous retrouver avec une arborescence pleine de dossiers vides, en plus des quelques dossiers contenant les fichiers que vous souhaitez.

8
Neil

Merci aux réponses précédentes. :)

Ce script nommé "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

Il accepte les variables de "Source", "Destination" et "Nom de fichier". Il ne peut également copier que des types de fichiers spécifiés ou des noms de fichiers sélectifs.

Toute amélioration est la bienvenue. :)

7
Rhak Kahr

Avec find et cp uniquement:

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 ";"
5
Rop

Semblable à la solution de Paulius, mais les fichiers qui ne vous intéressent pas ne sont pas copiés puis supprimés:

@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
4
Patrick Cuff

Ce n'est que deux commandes simples, mais je ne le recommanderais pas, sauf si les fichiers que vous n'avez PAS besoin de copier sont petits. En effet, cela copiera TOUS les fichiers, puis supprimera ceux qui ne sont pas nécessaires à la copie.

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"

Bien sûr, la deuxième commande est un peu longue, mais ça marche!

En outre, cette approche ne vous oblige pas à télécharger et à installer des outils tiers (Windows 2000+ BATCH dispose de suffisamment de commandes pour cela).

3
Paulius

Sous Linux et d’autres systèmes UNIX, l’utilisation de la commande tar suffirait facilement.

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

Ensuite, vous êtes arrivé à la cible et:

$ tar xvf /tmp/full-structure.tar 

Vous pouvez bien sûr diriger la sortie du premier goudron vers le second, mais le voir fonctionner par étapes est plus facile à comprendre et à expliquer. Il me manque le cd nécessaire/nouveau/chemin/dans la commande suivante - je ne me souviens plus comment faire maintenant. Quelqu'un d'autre peut l'ajouter, espérons-le.

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

Tar (gnutar) est également disponible sur Windows, mais j'utiliserais probablement moi-même la méthode xcopy sur cette plate-forme.

2
JohnP

À l'aide de l'interface de ligne de commande WinRAR, vous pouvez copier les noms de fichiers et/ou les types de fichiers dans une archive. Ensuite, vous pouvez extraire cette archive à l'emplacement de votre choix. Cela préserve la structure de fichier d'origine.

J'avais besoin d'ajouter des fichiers d'image d'album manquants sur mon téléphone portable sans avoir à recopier la musique elle-même. Heureusement, la structure de répertoire était la même sur mon ordinateur et mon mobile!

J'ai utilisé:

   rar a -r C:\Downloads\music.rar X:\music\Folder.jpg
  • C:\Downloads\music.rar = Archive à créer
  • X:\music\= Dossier contenant des fichiers de musique
  • Folder.jpg = Nom du fichier que je voulais copier

Cela a créé une archive avec tous les fichiers Folder.jpg dans les sous-répertoires appropriés.

Cette technique peut également être utilisée pour copier des types de fichiers. Si les fichiers avaient tous des noms différents, vous pouvez choisir d'extraire tous les fichiers dans un seul répertoire. Des paramètres de ligne de commande supplémentaires peuvent archiver plusieurs types de fichiers.

Plus d'informations sur ce lien très utile http://cects.com/using-the-winrar-command-line-tools-in-windows/

1
Jim_Joat

Pour ceux qui utilisent Altap Salamander (gestionnaire de fichiers à 2 panneaux): dans les options du menu contextuel de la copie, spécifiez simplement les noms de fichiers ou les masques. Facile.

1
Hugo P
XCOPY /S folder1\data.Zip copy_of_folder1  
XCOPY /S folder1\info.txt copy_of_folder1

EDIT: Si vous souhaitez conserver les dossiers vides (vous semblez devoir relire votre message), utilisez/E au lieu de/S.

1
gkrogers

Je vais bien avec les expressions régulières, paresseux et peu enclin aux installations, alors j’ai créé un fichier de commandes qui crée le répertoire et les copie avec les commandes de Vanilla DOS. Cela semble laborieux mais plus rapide pour moi que de travailler avec Robocopy.

  1. Créez votre liste de fichiers source avec les chemins complets, y compris la lettre du lecteur, si nécessaire, dans un fichier texte.
  2. Activez les expressions régulières dans votre éditeur de texte.
  3. Ajoutez des guillemets doubles autour de chaque ligne en cas d'espaces - la chaîne de recherche (.*) Remplace la chaîne "\1" Et cliquez sur Remplacer tout.
  4. Créez deux lignes par fichier - une pour créer le répertoire, une pour copier le fichier (qqq sera remplacé par le chemin de destination) - chaîne de recherche (.*), Remplacez la chaîne md qqq\1\nxcopy \1 qqq\1\n, Puis cliquez sur Remplacer tout.
  5. Supprimez le nom de fichier des chemins de destination - recherchez \\([^\\^"]+)"\n remplacez \\"\n
  6. Remplacez dans le chemin de destination (dans cet exemple, A:\src Et B:\dest). Désactivez les expressions régulières, recherchez qqq"A:\src\, Remplacez B:\dest\, Puis cliquez sur Remplacer tout.

md créera des répertoires imbriqués. copy se comporterait probablement de la même manière que xcopy dans cet exemple. Vous voudrez peut-être ajouter/Y à xcopy pour supprimer les confirmations d’écrasement. Vous vous retrouvez avec un fichier batch comme ceci:

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

répété pour chaque fichier de votre liste d'origine. Testé sur Win7.

0
Chris