2009-05-14 17 views
5

Tak więc, wydaje się, że jest kilka pytań dotyczących usuwania plików/katalogów pasujących do określonych przypadków, ale szukam czegoś dokładnie odwrotnego: Usuń WSZYSTKO w folderze, KTÓRY NIE ZOSTAJE dopasuj moje dostarczone przykłady.Usuń wszystkie pliki/katalogi z wyjątkiem dwóch określonych katalogów

Na przykład, tutaj jest przykład drzewo katalogu:

. 
|-- coke 
| |-- diet 
| |-- regular 
| `-- vanilla 
|-- icecream 
| |-- chocolate 
| |-- cookiedough 
| |-- cupcake 
| | |-- file1.txt 
| | |-- file2.txt 
| | |-- file3.txt 
| | |-- file4.txt 
| | `-- file5.txt 
| `-- vanilla 
|-- lol.txt 
|-- mtndew 
| |-- classic 
| |-- codered 
| |-- livewire 
| | |-- file1.txt 
| | |-- file2.txt 
| | |-- file3.txt 
| | |-- file4.txt 
| | `-- file5.txt 
| `-- throwback 
`-- pepsi 
    |-- blue 
    |-- classic 
    |-- diet 
    `-- throwback 

Chcę usunąć wszystko, ale pliki w teście/lody/ciastko/i test/mtndew/Livewire /. Wszystko inne może się udać, łącznie ze strukturą katalogów. Jak mogę to osiągnąć? Języki Nie mam nic przeciwko temu będącemu w: bash lub python.

Odpowiedz

3

find „s -prune przychodzi do głowy, ale jest to ból zmusić go do pracy dla poszczególnych ścieżek (icecream/cupcake/) zamiast konkretnych katalogów (cupcake/).

Osobiście bym po prostu użyć cpio i twardych link (aby uniknąć konieczności ich kopiowania) plików w katalogach, które chcesz zachować do nowego drzewa, a następnie usunąć stary:

find test -path 'test/icecream/cupcake/*' -o -path 'test/mtndew/livewire/*' | cpio -padluv test-keep 
rm -rf test 

To także zachowa twoją istniejącą strukturę katalogów dla katalogów, które zamierzasz przechowywać.

0

użyć find.

Twój komenda będzie wyglądać mniej więcej tak:

find $directory \(-prune 'some pattern' \) -delete 
+0

próbowałem, i mówi co następuje: find/home/Phuzion/test/\\ (-prune 'lody/ciastko /' \\) Usuń nie znalezisko: ścieżki muszą poprzedzać wyrażenie – phuzion

+0

Od strony man dla znalezienia: "Ponieważ -delete implikuje -depth, nie możesz z pożytkiem używać -prune i -delete razem." –

+0

Poprawna składnia byłaby bardziej podobna do "find $ directory -path ./pepsi/diet -prune -o -exec some-command '{}' \;" w każdym razie, aby wyeliminować ten komunikat o błędzie. –

2

mógłby zrobić coś w oparciu o Python's os.walk function.

import os 
for root, dirs, files in os.walk(top, topdown=False): 
    for name in files: 
     os.remove(os.path.join(root, name)) 
    for name in dirs: 
     os.rmdir(os.path.join(root, name)) 

... po prostu dodać coś do ignorowania ścieżki, które Cię interesują

3

Wszystko "z wyjątkiem" jest powodem, dla którego mamy instrukcje if; i dlaczego lista katalogów os.walk jest zmienną listą.

for path, dirs, files in os.walk('root'): 
    if 'coke' in dirs: 
     dirs.remove('coke') 
     dirs.remove('pepsi') 
2

Przenieś rzeczy, które chcesz zatrzymać w innym miejscu, a następnie usuwaj to, co zostało.

0

oneliner do rozwiązania problemu:

find. | grep -v "test/icecream/cupcake /" | grep -v „test/mtndew/Livewire /” | xargs rm -r

usunięty, gdyż nie działa

to może Ci w kłopoty, jeśli mają nazwy plików z przestrzeni w nich, i może utrzymać więcej plików, które chcesz, jeśli są inne drzewa, które pasują do wzorców.

Nieco lepsze rozwiązanie:

find . |sed "s/.*/rm '&'/"|grep -v "rm './test/icecream/cupcake/"| grep -v "rm './test/mtndew/livewire/"|sh 

faktycznie nie testowane, jeśli łamie pojawi się zachować obie części.

Edit: Jak wskazuje jego Dennis nie tylko dwie części, które rozkłada się :-) Poprawiono literówki w drugim przykładzie i usunął pierwszy

+0

W twoim pierwszym przykładzie będzie to rm -r test/icecream, który będzie zawierał ciastko (na przykład). Tak więc, mimo że masz grep -v cupcakes, nadal "jedzą". Drugi przykład ma kilka literówek i niezbilansowanych pojedynczych cudzysłowów.Powinno być miejsce po sed, a zero powinno być znakiem ampersand. –

+0

Nad ścieżkami nadal występują niezrównoważone pojedyncze cudzysłowy. Na przykład powinien to być "rm" ./test/icecream/cupcake/ '" –

5

Polecenie pozostawi tylko wybrane pliki w oryginalnych katalogach:

find test \(! -path "test/mtndew/livewire/*" ! -path "test/icecream/cupcake/*" \) -delete 

Nie potrzeba cpio. Działa na Ubuntu, Debian 5 i Mac OS X.

W systemie Linux, zgłosi, że nie może usunąć niepustych katalogów, co jest dokładnie pożądanym rezultatem. W systemie Mac OS X zrobi to po cichu.

+0

To znajduje test i usuwa go, usuwając katalogi, które próbujesz zapisać. –

+0

To znajduje test i NIE usuwa go, ponieważ nie jest pusty. Czy istnieją jakieś nowoczesne smaki Linuksa lub Uniksa, w których to polecenie nie działa? –

+0

Przepraszamy, popełniłem błąd podczas konfigurowania testu w moim systemie. Twój przykład działa poprawnie dla mnie. –

0

To działa dla mnie z find przy użyciu dwóch kroków: najpierw usuń pliki dozwolone, a następnie ich puste katalogi!

find -x -E ~/Desktop/test -not \(-type d -regex '.*/(cupcake|livewire)/*.*' -prune \) -print0 | xargs -0 ls -1 -dG 

# delete the files first 

# Mac OS X 10.4 
find -x -E ~/Desktop/test -not \(-type d -regex '.*/(cupcake|livewire)/*.*' -prune \) -type f -exec /bin/rm -fv '{}' \; 

# Mac OS X 10.5 
find -x -E ~/Desktop/test -not \(-type d -regex '.*/(cupcake|livewire)/*.*' -prune \) -type f -exec /bin/rm -fv '{}' + 

# delete empty directories 
find -x ~/Desktop/test -type d -empty -delete 
+0

Na ubuntu, find nie posiada -x-E, więc odpowiednik będzie następujący: find ~/Desktop/test -xdev -regextype posix-extended-not \ (-type d -regex '. */(Cupcake | livewire) /*.* '-prune \) -print0 | xargs -0 ls -1 -dG –

+0

Ponadto, może być konieczne w niektórych przypadkach, aby chronić puste katalogi, które chcesz nadal używać tego samego wyrażenia regularnego w komendzie find-pusty, która jest w ostatnim kroku w twojej odpowiedzi. Możesz wyjaśnić, że twoje pierwsze polecenie jest testem na dowód koncepcji i w inny sposób nie jest częścią dwóch kroków, które demonstrujesz. –

0

Jak inni Użyłem os.walk i os.path.join zbudować listę plików do usunięcia z fnmatch.fnmatch aby wybrać pliki, które muszą zostać włączone lub wyłączone:

#-------------------------------# 
# make list of files to display # 
#-------------------------------# 
displayList = [] 
for imageDir in args : 
    for root,dirs,files in os.walk(imageDir) : 
     for filename in files : 
      pathname = os.path.join(root, filename) 
      if fnmatch.fnmatch(pathname, options.includePattern) : 
       displayList.append(pathname) 


#----# now filter out excluded patterns #----# 
try : 
    if len(options.excludePattern) > 0 : 
     for pattern in options.excludePattern : 
      displayList = [pathname for pathname in displayList if not fnmatch.fnmatch(pathname, pattern) ] 
except (AttributeError, TypeError) : 
    pass 

Jeśli fnmatch nie wystarczy, możesz użyć modułu re do testowania wzorców.

Tutaj zbudowałem listę plików, zanim zrobię cokolwiek z nią, ale możesz przetwarzać pliki podczas ich generowania.

Blok try/except ... jest na wypadek, gdyby moja instancja klasy opcji nie miała wzorca wykluczającego lub powodowała wyjątek w fnmatch, ponieważ jest to niewłaściwy typ.

Ograniczeniem tej metody jest to, że zawiera pierwszy pliki dopasowania wzorca, następnie wyłącza. Jeśli potrzebujesz więcej elastyczności niż to (włącz pasujący wzorzec a, ale nie wzorzec b, chyba że wzorzec c ...) dobrze, to powyższy fragment nie jest do tego wystarczający. W rzeczywistości, pracując nad tym ćwiczeniem, zaczynasz rozumieć, dlaczego składnia polecenia find jest taka, jak jest. Wydaje się nieostrożny, ale w rzeczywistości jest to dokładnie sposób na zrobienie tego.

Ale jeśli wygenerujesz listę, możesz ją odfiltrować zgodnie z wymaganymi regułami włączania/wyłączania.

Jedną z zalet tworzenia listy jest możliwość jej sprawdzenia przed usunięciem. Jest to rodzaj opcji "--dryrun". Możesz to zrobić interaktywnie w interpreterze pythona, wydrukować listę, aby zobaczyć, jak wygląda, zastosować następny filtr, zobaczyć, czy został usunięty za dużo lub za mało i tak dalej.

2
find /path/to/test/ -depth -mindepth 1 \ 
! -path "/path/to/test/icecream/cupcake/*" \ 
! -path "/path/to/test/icecream/cupcake" \ 
! -path "/path/to/test/icecream" \ 
! -path "/path/to/test/mtndew/livewire/*" \ 
! -path "/path/to/test/mtndew/livewire" \ 
! -path "/path/to/test/mtndew" 
-delete -print 

Trochę nudne jest pisanie wszystkich ścieżek do zachowania, ale to jedyny sposób na użycie samego znalezienia.

Powiązane problemy