Comment copier une structure de répertoires mais n'inclure que certains fichiers (à l'aide de fichiers batch Windows)

103

Comme le titre l'indique, comment puis-je copier récursivement une structure de répertoires mais n'inclure que certains fichiers. Par exemple, étant donné la structure de répertoires 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 des répertoires. Comment puis-je copier la structure complète du répertoire, mais n'inclure que les fichiers nommés data.zip et info.txt (tous les autres fichiers doivent être ignorés)?

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

copy_of_folder1
  folder2
    folder3
      data.zip
      info.txt
    folder4
    folder5
      data.zip
M4N
la source

Réponses:

169

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

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

EDIT: Changement du /Sparamètre /Epour inclure les dossiers vides.

aphorie
la source
Puis-je copier * .zip avec cette syntaxe? J'ai essayé d'écrire simplement * .zip au lieu de data.zip, mais cela n'a pas copié les fichiers, seulement les dossiers. J'ai aussi essayé? .Zip
Niels Brinch
@Niels Brinch Oui, vous devriez pouvoir le faire. Quelle est la ligne de commande exacte que vous utilisez?
aphoria le
1
ROBOCOPY C: \ Source C: \ Destination * .zip / E
Niels Brinch
Bizarre. Quel système d'exploitation utilisez-vous? Avez-vous les autorisations de fichier / dossier nécessaires? Je viens de tester sur Win 7 et *.zipj'ai travaillé pour moi.
aphoria le
Vraiment!? J'utilise également Win 7. Quand j'essaye, il ne copie aucun fichier. Seuls les dossiers. Je vais essayer de nouveau. (pendant que nous y sommes, quelle est la syntaxe pour inclure plus de * .zip - disons * .zip et * .jpg.
Niels Brinch
29

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 for externe génère toute combinaison de chemin possible de sous-répertoire in SOURCE_DIRet name in FILENAMES_TO_COPY. Pour chaque fichier existant, xcopy est appelé. FILE_INTERMEDIATE_DIRcontient le chemin du sous-répertoire du fichier dans SOURCE_DIRlequel doit être créé DEST_DIR.

Sakra
la source
1
J'avais besoin de copier toutes les photos des dossiers et sous-dossiers, ce script batch m'a aidé. Je viens de changer la ligne set FILENAMES_TO_COPY=data.zip info.txtci-dessus enset FILENAMES_TO_COPY=*.jpg
Kai Noack
J'obtiens une erreur car le chemin du fichier contient des espaces (SOURCE_DIR = "C: \ Origin Test", DEST_DIR = "C: \ Dest Test", error: Test "" était inattendu à ce moment). J'ai essayé de changer% var% par! Var! partout, mais sans succès. Des indices sur la façon de résoudre cela? Toute la structure est pleine de noms de dossiers avec des espaces.
ricardo.scholz
1
Essayez set "SOURCE_DIR=C:\Origin Test"et set "DEST_DIR=C:\Dest Test". Notez l'emplacement des guillemets doubles.
sakra
13

essayez de rediriger la sortie 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 - c'est donc sûr et rapide.

supprimez -v pour une opération plus rapide, une fois que vous vous y êtes habitué.

Gabe Rainbow
la source
2
@Christian il a une dépendance sur cpio qui ne fait pas partie de l'installation standard.
Crashworks
8

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. Vous pourriez donc vous retrouver avec une arborescence pleine de dossiers vides, en plus des quelques dossiers contenant les fichiers souhaités.

Neil
la source
L'exécuter une deuxième fois changera la destination. (Il met les fichiers dans un sous-dossier.) C'est un comportement idiot si vous me demandez. Vous voudrez exécuter rm -r -ErrorAction:SilentlyContinue d:\destinationPathavant de copier pour résoudre ce problème.
MakotoE
7

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 "Source", "Destination" et "FileName". Il ne peut également copier que le type spécifié de fichiers ou des noms de fichiers sélectifs.

Toute amélioration est la bienvenue. :)

Rhak Kahr
la source
5

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 ";"
Rop
la source
4

Similaire à 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
Manchette Patrick
la source
4

Pour copier tous les fichiers texte dans G: et conserver la structure des répertoires:

xcopy *.txt /s G:
Osbert Snudge
la source
cela peut-il fonctionner de manière récursive, comme la copie de tous les fichiers .txt des sous-dossiers et la préservation de la structure des répertoires par rapport au répertoire de base?
Micka
3

Ce ne sont que deux commandes simples, mais je ne le recommanderais pas, à moins que les fichiers que vous n'avez PAS besoin de copier soient petits. C'est parce que cela copiera TOUS les fichiers, puis supprimera les fichiers qui ne sont pas nécessaires dans 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 assez longue, mais ça marche!

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

Paulius
la source
Merci beaucoup. Comme vous l'avez mentionné, ce n'est pas idéal, car (dans mon cas) les fichiers qui doivent être copiés sont généralement petits, tandis que les fichiers qui ne doivent pas être copiés sont plus gros (et il peut y en avoir beaucoup).
M4N
2

Sous Linux et d'autres systèmes UNIX, l'utilisation de la tarcommande le ferait facilement.

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

Ensuite, vous cwd à la cible et:

$ tar xvf /tmp/full-structure.tar 

Bien sûr, vous pouvez diriger la sortie du premier tar vers le second, mais le voir fonctionner par étapes est plus facile à comprendre et à expliquer. Il me manque le cd / to / new / path / nécessaire dans la commande suivante - je ne me souviens simplement pas comment le 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 la xcopyméthode moi-même sur cette plate-forme.

JohnP
la source
tar cvf /tmp/full-structure.tar ** / data.zip ** / info.txt a fonctionné pour moi
ssinganamalla
«Tar cvf /tmp/full-structure.tar ** / data.zip ** / info.txt» et «tar cvf /tmp/full-structure.tar * data.zip * info.txt» m'ont donné 3 erreurs : (1) "tar: * data.zip: impossible de stat: aucun fichier ou répertoire de ce type", (2) "tar * info.txt: impossible de stat: aucun fichier ou répertoire de ce type", (3) "tar: sortie avec état d'échec en raison d'erreurs précédentes ". À partir de quel dossier dois-je faire tout cela? Je ne comprends pas cette méthode.
user1271772
La question dit WINDOWS
Anfelipe
Win10 a WSL, ce qui le rend valide. tar est disponible sur Windows depuis plus de 20 ans et l'utilisation d'un tube fonctionne depuis les jours MS-DOS. Dans tout environnement shell, le PWD est important. PWD - répertoire de travail actuel. J'admets que cette solution est moins pour les utilisateurs finaux et plus pour les utilisateurs expérimentés ou les programmeurs.
JohnP
1
XCOPY /S folder1\data.zip copy_of_folder1  
XCOPY /S folder1\info.txt copy_of_folder1

EDIT: Si vous souhaitez conserver les dossiers vides (qui, en relisant votre message, vous semblez utiliser) / E au lieu de / S.

gkrogers
la source
1
il ne préserve pas la structure des dossiers.
Paulius
L'option / E préserve la structure des dossiers, y compris la création de dossiers vides si nécessaire. Le nom de fichier fonctionne également avec un caractère générique (par exemple, dossier1 \ *. Zip). Je n'obtiens le message "Erreur de fichier non trouvé" que lorsque je lui transmets un nom de fichier complet qui n'existe pas (auquel cas j'obtiens "Fichier non trouvé - xxx.xxx 0 Fichier (s) copié (s)". Quand je lui donne un modèle qui ne renvoie aucun fichier (par exemple, dossier1 \ *. zzz), je reçois juste "0 fichier (* s) copié".
gkrogers
1

À 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 à mon téléphone portable sans avoir à recopier la musique elle-même. Heureusement, la structure des répertoires é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 musicaux
  • Folder.jpg = Nom de 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 dans ce lien très utile http://cects.com/using-the-winrar-command-line-tools-in-windows/

Jim_Joat
la source
1

Pour ceux qui utilisent Altap Salamander (gestionnaire de fichiers 2 panneaux): dans les Options de la popup Copier, il suffit de spécifier les noms de fichiers ou les masques. Facile.

Hugo P
la source
0

Je suis d'accord avec les expressions régulières, paresseux et opposé aux installations, j'ai donc créé un fichier de commandes qui crée le répertoire et des copies avec des commandes DOS vanille. Cela me semble laborieux mais plus rapide que de travailler sur la robocopie.

  1. Créez votre liste de fichiers source avec des chemins complets, y compris la lettre de lecteur si nécessaire, dans un fichier texte.
  2. Activez les expressions régulières dans votre éditeur de texte.
  3. Ajouter des guillemets doubles autour de chaque ligne en cas d'espaces - la chaîne de recherche (.*)remplace la chaîne"\1" et cliquez sur tout remplacer
  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) - la chaîne de recherche (.*)remplace la chaîne md qqq\1\nxcopy \1 qqq\1\net cliquez sur remplacer tout
  5. Supprimer le nom de fichier des chemins de destination - \\([^\\^"]+)"\nremplacement de la recherche\\"\n
  6. Remplacez dans le chemin de destination (dans cet exemple A:\srcet B:\dest). Désactivez les expressions régulières, recherchez qqq"A:\src\remplacer B:\dest\et cliquez sur tout remplacer.

md créera des répertoires imbriqués. copy se comporterait probablement de la même manière que xcopy dans cet exemple. Vous pouvez 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.

Chris
la source
-1

Pour ce faire par glisser-déposer, utilisez winzip, il existe une option de préservation de la structure dir. Créez simplement un nouveau .zip au niveau du répertoire qui sera votre racine et faites-y glisser les fichiers.

Gnoy Dav
la source
Merci, mais je cherchais une solution à utiliser à partir de fichiers de script (batch). Donc, pas de glisser-déposer ...
M4N