Skopiować tylko foldery, a nie pliki?

16

Czy istnieje sposób na skopiowanie całego katalogu, ale tylko folderów? Mam gdzieś w katalogu uszkodzony plik, który powoduje awarię dysków twardych.

Zamiast kopiować uszkodzony plik na inny dysk twardy, chciałem po prostu skopiować foldery, ponieważ mam skrypty wyszukujące setki folderów i nie chcę ręcznie tworzyć ich wszystkich.

Przeszukałem instrukcję cp, ale nic nie widziałem (mogłem to przegapić)

Powiedzmy, że mam tę strukturę na moim uszkodzonym dysku twardym:

dir1
    files
    dir2
        files
        files
        dir4
dir3
files

Chcę tylko struktury katalogów, a nie żadnych plików.

Skończyło się na nowym dysku twardym:

dir1
    dir2
        dir4
dir3

Mam nadzieję, że ktoś zna jakieś sztuczki!

Shannon
źródło
Czy masz na myśli, że chcesz po prostu skopiować strukturę katalogu, czy po prostu chcesz wykluczyć pliki z bieżącego katalogu roboczego (a wszystkie inne pliki w głębszych podkatalogach są grą)?
Oli
Dodałem przykład. przepraszam za mylące
Shannon,
1
FYI służy rsyncdo kopiowania struktury katalogów ORAZ zachowania uprawnień i atrybutów] ( stackoverflow.com/a/9242883/52074 ). Używanie zwykłego mkdir -p nie zachowuje uprawnień i atrybutów .
Trevor Boyd Smith

Odpowiedzi:

15

Jeśli chcesz wykonać kopię lustrzaną szkieletu katalogu i nie kopiować żadnych plików:

find -type d -links 2 -exec mkdir -p "/path/to/backup/{}" \;

Co tu się dzieje:

  • Znajdź to tylko wybieranie katalogów
  • Używamy, -links 2aby znaleźć najgłębsze możliwe katalogi .
  • mkdir -p utworzy po drodze brakujące katalogi.

Zrobiłem to w ten sposób, a nie find -type d -exec mkdir -p "/path/to/backup/{}" \;dlatego, że ograniczy to cały zestaw mkdirpołączeń. Możemy to szybko udowodnić za pomocą małego testu. Oto drzewo testowe, a następnie to, co uruchomiłem, aby porównać dwa polecenia:

$ tree
.
├── dir1
│   ├── dir2
│   │   └── dir3
│   ├── dir7
│   └── dir8
└── dir9
    └── dir0

$ pr -m -t <(find -type d) <(find -type d -links 2)
.                               ./dir1/dir8
./dir1                          ./dir1/dir2/dir3
./dir1/dir8                     ./dir1/dir7
./dir1/dir2                     ./dir9/dir0
./dir1/dir2/dir3
./dir1/dir7
./dir9                  
./dir9/dir0 

A to tylko poprawi się w rozwiązaniu opartym na prawdziwych słowach z tysiącami katalogów.

Oli
źródło
To ja jestem noobem, ale jak przeszukujesz stary katalog, aby skopiować do kopii zapasowej? Widzę tu tylko jedną ścieżkę
Shannon,
Jeśli nie określisz ścieżki, findużyje bieżącego katalogu roboczego jako punktu początkowego. Jeśli chcesz użyć innej ścieżki, użyj składni:find /path/to/search/ -type.....
Oli
Więc ustawiłem mój katalog na określony folder zawierający szkielet, który chcę skopiować, uruchomić find -type d -exec mkdir -p "/media/jinglez/TVSeries/TV Series"/{}" \;i wszystko powinno być w porządku? Wydaje się, że zajmuje to trochę czasu: /
Shannon
Uruchamiam to z normalnego terminala, prawda?
Shannon,
1
Oba są specyficzne dla klauzuli exec find. {} oznacza bieżącą „znalezioną” nazwę pliku i \; jest tylko ucieczką do zakończenia klauzuli. Wygląda na to, że w kodzie znajduje się dodatkowy „do niczego dobrego, jestem pewien ... Powinien przeczytać:find -type d -links 2 -exec mkdir -p "/media/jinglez/TVSeries/TV Series/{}" \;
Oli
2

Całkiem łatwo zrobić z python one-liner:

bash-4.3$ tree
.
├── ABC
├── set_pathname_icon.py
├── subdir1
│   ├── file1.abc
│   └── file2.abc
├── subdir2
│   ├── file1.abc
│   └── file2.abc
└── subdir3
    └── subdir4
        └── file1.txt

4 directories, 7 files
bash-4.3$ python -c 'import os,sys;dirs=[ r for r,s,f in os.walk(".") if r != "."];[os.makedirs(os.path.join(sys.argv[1],i)) for i in dirs]' ~/new_destination
bash-4.3$ tree ~/new_destination
/home/xieerqi/new_destination
├── subdir1
├── subdir2
└── subdir3
    └── subdir4

Jako skrypt można to przepisać w następujący sposób:

#!/usr/bin/env python
import os,sys
dirs=[ r for r,s,f in os.walk(".") if r != "."]
for i in dirs:
    os.makedirs(os.path.join(sys.argv[1],i)) 
Sergiy Kolodyazhnyy
źródło