Question Déplacer récursivement des fichiers dans des sous-répertoires vers de nouveaux sous-répertoires du même nom


J'ai un lot de fichiers tous se terminant par la même chaîne, à savoir: *_ext.dat situé dans plusieurs sous-répertoires avec plusieurs autres fichiers, dans un répertoire principal donné. C'est la structure:

/main_dir/subdir1/file11_ext.dat
/main_dir/subdir1/file12_ext.dat
/main_dir/subdir1/file13_ext.dat
/main_dir/subdir1/file14_other.dat
/main_dir/subdir1/file15_other.dat

/main_dir/subdir2/file21_ext.dat
/main_dir/subdir2/file22_ext.dat
/main_dir/subdir2/file23_ext.dat
/main_dir/subdir2/file24_other.dat
/main_dir/subdir2/file25_other.dat

/main_dir/subdir3/file31_ext.dat
/main_dir/subdir3/file32_ext.dat
/main_dir/subdir3/file33_ext.dat
/main_dir/subdir3/file34_other.dat
/main_dir/subdir3/file35_other.dat

Je dois bouger récursivement seulement les fichiers se terminant par *_ext.dat dans un nouveau répertoire principal, new_dir, en respectant la structure du sous-répertoire, les fichiers se retrouveront dans une structure de répertoire équivalente à celle-ci:

/new_dir/subdir1/file11_ext.dat
/new_dir/subdir1/file12_ext.dat
/new_dir/subdir1/file13_ext.dat

/new_dir/subdir2/file21_ext.dat
/new_dir/subdir2/file22_ext.dat
/new_dir/subdir2/file23_ext.dat

/new_dir/subdir3/file31_ext.dat
/new_dir/subdir3/file32_ext.dat
/new_dir/subdir3/file33_ext.dat

Pour cette raison, la commande devrait également créer ces sous-répertoires avec leurs noms correspondants. Je le sais avec une ligne comme celle-ci:

find . -name "*_ext.dat" -print0 | xargs -0 rm -rf

je peux effacer tous ces fichiers, mais je ne sais pas comment le modifier pour faire ce dont j'ai besoin (ou même si c'est possible).


2
2017-10-08 23:55


origine


Probablement quelque chose comme rsync --include=*_ext.dat /main_dir/ /new_dir/ fera le tour. Je ne l'ai pas testé cependant. - Jaap Eldering


Réponses:


Je voudrais d'abord créer les sous-répertoires dans new_dir par

cd main_dir
for i in *; do mkdir "../new_dir/$i"; done
cd ..

Ensuite, vous pouvez utiliser bash's for commande à nouveau avec l'expansion de modèle pour faire exactement ce dont vous avez besoin rapidement:

for i in main_dir/*/*_ext.dat; do cp "$i" "new_dir${i##main_dir}"; done

en utilisant le fait que les répertoires de destination existent. Enfin, s’il n’était pas garanti que chaque d'entre eux seraient effectivement utilisés, vous pouvez purger les vides après:

cd new_dir
rmdir --ignore-fail-on-non-empty *

1
2017-11-11 01:37



Dans la première boucle vous vous attendez à ce que dans le main_dir il n'y a que des répertoires. De plus, vous ne doublez pas les chemins d'accès dans tout votre code, de sorte qu'il ne fonctionnera pas avec les noms de fichiers contenant des espaces. Ce code sera beaucoup plus robuste: for i in */; do mkdir "../new_dir/$i"; done. --- Le dernier morceau de code ne supprimera pas les répertoires contenant des répertoires vides. Pour cela, vous pouvez utiliser find: Comment supprimer les répertoires vides imbriqués en utilisant un script Bash sous Linux? - pabouk
@pabouk Bien sûr que oui. (Peut-être que vous n'avez pas remarqué la cd le précédant?) Man page of rmdir dit: "DESCRIPTION ... Supprimer le (s) RÉPERTOIRE (S), s’ils sont vides." L'option --ignore-fail-on-non-empty opte pour les avertissements que les répertoires non vides ont été omis. De plus, je l'ai essayé sur mon système avant de poster. - The Vee
De plus, la structure de répertoires attendue par mes commandes est parfaitement compatible avec la manière dont l’OP l’a introduit, y compris ses exemples explicites. Bien sûr, les commandes seraient différentes si la structure l'était. - The Vee
Merci cependant pour le commentaire sur les espaces. Fixé. - The Vee
Je vous en prie. Vous avez exagéré avec les guillemets doubles. La dernière commande ne fera pas ce que vous voulez. --- Première boucle: N'est-il pas préférable d'ajouter un seul / pour que le code soit plus universel et fonctionne dans plus de cas d'utilisation? --- Dernière commande ne marche pas: mkdir a ; cd a ; mkdir -p a/b/c d/e/f g/h/i ; ls ; rmdir --ignore-fail-on-non-empty * ; ls --- sortie: a d g  a d g - pabouk