Jak wyodrębnić konkretnie nazwany folder z katalogu rekurencyjnego, usunąć pozostałe?

10

Mam tego rodzaju drzewo katalogów uzyskane z rozpakowania pliku zip:

x -> y -> z -> run -> PLIKI I DIRECTORIES TUTAJ

Są więc 4 katalogi, z których 3 są puste z plików (x, y, z) i zawierają tylko 1 podkatalog, i jest katalog, który mnie interesuje, o nazwie „ uruchom ”.

Chcę przenieść sam katalog „run” (w tym wszystko wewnątrz) do lokalizacji „root”, w której rozpakowałem (tj. Gdzie jest „x”, ale nie wewnątrz „x”).

Założenia: Nie istnieje folder o nazwie „run”, ale nie wiem, jak wiele katalogów będę musiał „cd”, aby dostać się do niego (może być 3 (x, y, z), może być 10 lub więcej nazw. są również nieznane i nie muszą być x, y, z itp.).

Jak mogę to osiągnąć? Próbowałem wielu odmian tego pytania, ale wszystkie zawiodły.

Idos
źródło
1
Obawiam się, że obraz nie jest bardzo wyraźny, nie. Nie publikuj zrzutów ekranu z tekstem . Zamiast tego wklej tekst bezpośrednio do pytania i użyj narzędzi formatujących . Nie mogę nawet odczytać nazwy katalogu na twoim zdjęciu. Widzę tylko niewyraźne niebieskie rozmycie.
terdon

Odpowiedzi:

14

co powiesz na

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

gdzie

  • / path / to / X to katalog docelowy
  • zaczynasz z tego samego miejsca.
  • następnie użyj innej odpowiedzi, aby usunąć puste katalogi.

(na bocznej notatce jest --junk-pathsdostępna opcja zip, podczas zipowania lub rozpakowywania)

Archemar
źródło
7

Zrobiłbym to bashza pomocą globstar. Jak wyjaśniono w 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.

Aby przenieść katalog rundo katalogu najwyższego poziomu x, a następnie usunąć resztę, możesz:

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

shoptKomenda umożliwia globstaropcję. mv x/**/run/ x/Ruszy żadnych podkatalogów nazwanych run(zauważ, że to działa tylko wtedy, gdy istnieje tylko jeden runkatalog) do xi findusunie żadnych pustych katalogów.

Możesz zrobić wszystko w powłoce z rozszerzonym globowaniem, jeśli chcesz, ale wolę siatkę bezpieczeństwa, find -emptyaby upewnić się, że żadne niepuste katalogi nie zostaną usunięte. Jeśli Cię to nie obchodzi, możesz użyć:

shopt -s globstar; shopt -s extglob; mv x/**/run/ x/ && rm -rf x/!(run)
terdon
źródło
6

Zdecydowanie bardziej szczegółowy, ale wykonujący pracę w jednym kroku:

Zakładając, że masz zainstalowany 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]))

Jak używać

  1. Skopiuj skrypt do pustego pliku i zapisz go jako get_folder.py
  2. Uruchom go z katalogiem głównym (zawierającym rozpakowane pliki) i nazwą folderu, aby „podnieść” jako argumenty:

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

I to jest zrobione:

wprowadź opis zdjęcia tutaj

wprowadź opis zdjęcia tutaj

Jacob Vlijm
źródło
To bardzo interesujące rozwiązanie, ale z różnych powodów wolę nie używać żadnego skryptu Pythona. Dziękuję ci!
Idos,
Nie ma problemu. Może przyda się każdemu innemu. Ciekawe dlaczego? Jestem pewien, że wiele aplikacji już używa Pythona.
Jacob Vlijm,
Głównie odkąd umieszczenie pliku .py w dowolnym miejscu będzie problematyczne, ponieważ muszę założyć, że znajduje się on w tym samym miejscu dla każdej maszyny linuxowej, która będzie uruchamiała mój skrypt (a mój skrypt działa na wielu platformach).
Idos,
@Idos tylko ciekawy, które platformy? Python jest dość rozpowszechniony. Nie sądzę, że jest domyślnie zainstalowany na Mac OS X, ale większość dystrybucji Linuksa go ma
Sergiy Kolodyazhnyy
4

Rozwiązanie Perla

#!/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");

Sposób działania jest prosty: find()podprogram przejdzie rekurencyjnie do podanego drzewa katalogów, znajdzie katalog o nazwie runi wrzuci go do tablicy poszukiwanych nazw plików. W tym przypadku zakładamy, że na liście powinien znajdować się tylko jeden plik, dlatego po zakończeniu polecenia korzystamy dirmove()z File::Copy::Recursivemodułu i przenosimy go do bieżącego katalogu roboczego, z którego został wywołany skrypt. Zatem w twoim przypadku wywołałbyś go z katalogu nadrzędnego do x.

Oryginalne drzewo katalogów:

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

Wynik:

$ ~/find_dir.pl .  
$ tree 
.
├── levelone
│   └── leveltwo
│       └── levelthree
└── run
    ├── file1
    ├── file2
    └── file3
Sergiy Kolodyazhnyy
źródło