Comment extraire un dossier spécifiquement nommé d'un répertoire récursif, supprimer les autres?

10

J'ai ce type d'arborescence de répertoires qui est obtenu en décompressant un fichier zip:

x -> y -> z -> run -> FICHIERS ET RÉPERTOIRES ICI

Il y a donc 4 répertoires, dont 3 sont vides de fichiers (x, y, z) et ne contiennent qu'un seul sous-répertoire, et il y a le répertoire qui m'intéresse, nommé " run ".

Je veux déplacer le répertoire "run" lui-même (y compris tout ce qu'il contient) à l'emplacement "root" où j'ai décompressé (c'est-à-dire où "x" est, mais pas à l'intérieur de "x").

Hypothèses: Il existe un dossier nommé "run", mais je ne sais pas combien de répertoires je devrai "cd" pour y accéder (peut être 3 (x, y, z), peut être 10 ou plus. Les noms sont également inconnus et ne doivent pas nécessairement être x, y, z, etc.).

Comment puis-je accomplir cela? J'ai essayé de nombreuses variantes de cette question, mais elles ont toutes échoué.

Idos
la source
1
J'ai bien peur que l'image ne soit pas très claire, non. Veuillez ne pas publier de captures d'écran de texte . Au lieu de cela, collez le texte directement dans votre question et utilisez les outils de mise en forme . Je ne peux même pas lire le nom du répertoire sur votre photo. Tout ce que je vois, c'est un flou bleu sombre.
terdon

Réponses:

14

qu'en est-il de

  find . -type d -name run -exec mv {} /path/to/X \;

  • / path / to / X est votre répertoire de destination
  • vous partez de ce même endroit.
  • puis utilisez une autre réponse pour supprimer les répertoires vides.

(sur une note latérale, il y a une --junk-pathsoption dans zip, que ce soit lors du zip ou du dézippage)

Archemar
la source
7

Je le ferais en bashutilisant globstar. Comme expliqué dans man bash:

globstar
      If set, the pattern ** used in a pathname expansion con‐
      text will match all files and zero or  more  directories
      and  subdirectories.  If the pattern is followed by a /,
      only directories and subdirectories match.

Ainsi, pour déplacer le répertoire runvers le répertoire de niveau supérieur x, puis supprimer le reste, vous pouvez faire:

shopt -s globstar; mv x/**/run/ x/  && find x/ -type d -empty -delete

La shoptcommande active l' globstaroption. Le mv x/**/run/ x/déplacera tous les sous-répertoires nommés run(notez que cela ne fonctionne que s'il n'y a qu'un seul runrépertoire) dans xet findsupprimera tous les répertoires vides.

Vous pouvez faire tout cela dans le shell avec un globbing étendu, si vous le souhaitez, mais je préfère le filet de sécurité de find -emptypour être sûr qu'aucun répertoire non vide n'est supprimé. Si cela vous est égal, vous pouvez utiliser:

shopt -s globstar; shopt -s extglob; mv x/**/run/ x/ && rm -rf x/!(run)
terdon
la source
6

Certainement plus verbeux, mais faire le travail en une seule étape:

En supposant que vous avez installé python

#!/usr/bin/env python3
import shutil
import os
import sys

dr = sys.argv[1]

for root, dirs, files in os.walk(dr):
    # find your folder "run"
    for pth in [d for d in dirs if d == sys.argv[2]]:
        # move the folder to the root directory
        shutil.move(os.path.join(root, pth), os.path.join(dr, pth))
        # remove the folder (top of the tree) from the directory
        shutil.rmtree(os.path.join(dr, root.replace(dr, "").split("/")[1]))

Comment utiliser

  1. Copiez le script dans un fichier vide, enregistrez-le sous get_folder.py
  2. Exécutez-le avec le répertoire racine (contenant vos fichiers décompressés) et le nom du dossier à "soulever" comme arguments:

    python3 /full/path/to/get_folder.py /full/path/to/folder_containing_unzipped_dir run
    

Et c'est fait:

entrez la description de l'image ici

entrez la description de l'image ici

Jacob Vlijm
la source
C'est une solution très intéressante mais je préfère ne pas utiliser de script python pour diverses raisons. Merci!
Idos
Aucun problème. C'est peut-être utile à quelqu'un d'autre. Curieux de savoir pourquoi cependant? Je suis sûr que de nombreuses applications utilisent déjà python.
Jacob Vlijm
Principalement, le fait de placer le fichier .py n'importe où sera problématique car je dois supposer qu'il se trouve au même endroit pour chaque machine Linux qui exécutera mon script (et mon script est exécuté sur de nombreuses plates-formes).
Idos
@Idos juste curieux, quelles plateformes? Python est assez répandu. Je ne pense pas qu'il soit installé sur Mac OS X par défaut, mais la plupart des distributions Linux l'ont
Sergiy Kolodyazhnyy
4

Solution Perl

#!/usr/bin/env perl
use strict;
use warnings;
use File::Find;
use File::Copy::Recursive qw(dirmove);

my @wanted;
find(sub{ -d $_ && $_ eq "run" && push @wanted,$File::Find::name}, $ARGV[0]);
dirmove("$wanted[0]","./run");

La façon dont cela fonctionne est simple: le find()sous-programme parcourt récursivement l'arborescence de répertoires donnée, trouve le répertoire dont le nom est runet le pousse dans un tableau de noms de fichiers souhaités. Dans ce cas, nous supposons qu'il ne devrait y avoir qu'un seul fichier dans la liste, donc une fois la commande terminée, nous utilisons à dirmove()partir du File::Copy::Recursivemodule et le déplaçons dans le répertoire de travail actuel à partir duquel le script a été appelé. Ainsi, dans votre cas, vous l'appelleriez du répertoire parent vers x.

Arborescence de répertoires d'origine:

$ tree                                                                                                                   
.
└── levelone
    └── leveltwo
        └── levelthree
            └── run
                ├── file1
                ├── file2
                └── file3

Résultat:

$ ~/find_dir.pl .  
$ tree 
.
├── levelone
│   └── leveltwo
│       └── levelthree
└── run
    ├── file1
    ├── file2
    └── file3
Sergiy Kolodyazhnyy
la source