Belirli bir alt dizin boşsa üst dizini (boş olmayan) silin


11

Belirli bir alt dizinde dosyaları içeren tüm dizini tutmak zorunda ama geri kalan alt dizini boş olan tüm dizinleri silmek zorunda.

Burada daha spesifik olmak gerekirse, yapı:

A
|
|--------312311
|       |
|       |----Recording
|       |----a.txt
|       |----b.txt
|
|
|--------453453
|       |----Recording
|                   |
|                   |-------a.mp3
|       |----a.txt
|       |----b.txt
|
|
|--------566532
|       |----Recording
|       |----a.txt
|       |----b.txt

Alt dizinler bir dosya içerebilir veya içermeyebilir. Bu yüzden '312311' & '566532' gibi tüm dizini silmeliyim ve sadece '453453' tüm verilerle birlikte bırakılmalıdır çünkü benim için belirli bir dizin olan 'Kayıt' klasöründe bir dosya var.

Birçok gönderi gördüm, ancak birçok özel dosya adına bağlanıyor. Bir haftada birçok kez yapmam gerektiğinden herhangi bir yardım çok takdir edilecektir.


Kayıt her zaman dizindeki ilk düzeyde mi? Ayrıca: tüm klasörler ana dizinin içindeki ilk düzeydedir?
Jacob Vlijm

A, numaralandırılmış dizinler içerdiği üst düzey dizindir. Numaralı dizinlerde 'Kayıt' klasörünün yanı sıra bazı 'txt' dosyalarını da içerir. Ve 'Kayıt' dosya içerebilir veya içermeyebilir ..
Derek James

Metninizin resmini kaldıracak ve asıl metni sorunuza yerleştirecek misiniz? Metin resimleri işlemek için kullanışsızdır. Gerçek metnin kullanılması, diğer doğal kolaylıkların yanı sıra çok daha uygundur.
LD James

aynısını sizden de istedim James ..
Derek James

Yanıtlar:


12

Aşağıdaki komut dosyası tam olarak açıkladığınız gibi olacaktır:

  1. bir dizindeki klasörleri listeler
  2. "Kayıt" adlı bir klasör için klasörlerin her birinin içine bakar

    • Varsa ve boşsa, üst klasörünü siler
    • o eğer değil mevcut, aynı zamanda üstün bir klasör siler
    • A'nın içindeki ilk düzeydeki dosyalar silinmeyecektir.

Bir resimde:

A
|
|--------123456
|       |
|       |----Recording
|       |----a.txt
|       |----b.txt
|
|
|--------635623
|       |----Recording
|                   |
|                   |-------a.mp3
|       |----a.txt
|       |----b.txt
|
|
|--------123456
|       |----Recording
|       |----a.txt
|       |----b.txt
|
|--------Monkey.txt

sonuçlanacak:

A
|
|
|--------635623
|       |----Recording
|                   |
|                   |-------a.mp3
|       |----a.txt
|       |----b.txt
|
|
|--------Monkey.txt

Senaryo

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

dr = sys.argv[1]

def path(*args):
    return os.path.join(*args)

for d in os.listdir(dr):
    try:
        if not os.listdir(path(dr, d, "Recording")):
            shutil.rmtree(path(dr,d))
    except FileNotFoundError:
        shutil.rmtree(path(dr,d))
    except NotADirectoryError:
        pass

Kullanmak

  1. Komut dosyasını boş bir dosyaya kopyalayın, delete_empty.py
  2. Komut tarafından bağımsız değişken olarak (full!) Diziniyle (alt dizinlerinizde containin, örneğinizde A ile) çalıştırın:

    python3 /path/to/delete_empty.py /path/to/directory
    

Bu kadar.

açıklama

"A" klasörünüzün içeriğini komut dosyasına beslemek,

os.listdir(dr)

alt dizinlerini (ve dosyalarını) listeler. Sonra:

if not os.listdir(path(dr, d, "Recording"))

(alt) klasörlerin her birinin içeriğini listelemeye çalışır; bu, öğe bir dosya ise bir hata oluşturur:

except NotADirectoryError
    pass

veya "Kayıt" klasörü hiç mevcut değilse:

FileNotFoundError
    shutil.rmtree(path(dr,d))

"Kayıt" klasörü varsa ve boşsa, üst klasör kaldırılır:

if not os.listdir(path(dr, d, "Recording")):
    shutil.rmtree(path(dr,d))

DÜZENLE

Ayrıca, yorumlarda istendiği gibi, birden çok alt dizini (adı) kontrol edecek bir sürüm.

Dizinin , listelenen (boş olmayan) alt dizinlerden herhangi birini içermesi durumunda, dizin tutulur. Aksi takdirde silinecektir.

Kullanmak

  1. Komut dosyasını boş bir dosyaya kopyalayın, delete_empty.py
  2. (Full!) Diziniyle (örneğinizde alt dizinlerinizi, A'yı içerir) ve alt dizinlerin adlarını komutla bağımsız değişken olarak çalıştırın:

    python3 /path/to/delete_empty.py /path/to/directory <subdir1> <subdir2> <subdir3>
    

Bu kadar.

Senaryo

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

dr = sys.argv[1]; matches = sys.argv[2:]

def path(*args):
    return os.path.join(*args)

for d in os.listdir(dr):
    # delete directory *unless* either one of the listed subdirs has files
    keep = False
    # check for each of the listed subdirs(names)
    for name in matches:
        try:
            if os.listdir(path(dr, d, name)):
                keep = True
                break
        except NotADirectoryError:
            # if the item is not a dir, no use for other names to check
            keep = True
            break
        except FileNotFoundError:
            # if the name (subdir) does not exist, check for the next
            pass
    if not keep:
        # if there is no reason to keep --> delete
        shutil.rmtree(path(dr,d))

Not

Lütfen tam olarak ne istediğinizi yaptığından emin olmak için bir test dizininde çalıştırın.


bu kod gerçekten yardımcı oldu ve söylendiği gibi çalıştı. Kod için teşekkürler. Gerçekten yardımcı.
Derek James

İki klasörü veya daha fazlasını saklamam ve kontrol etmem gerekiyorsa, bu kodda nasıl yapabilirim? 'VEYA' veya boru 'ekleme | 'bir yerde .. toplamayı öner!
Derek James

Merhaba @DerekJames sadece küçük bir düzenleme gerektiren, bu öğleden sonra yayınlayacağım.
Jacob Vlijm

@Derek, bekleyin, klasörlerden herhangi biri boşsa veya tümü boşsa üst klasör kaldırılmalı mı? Bir üst direkte birden fazla olabilir mi?
Jacob Vlijm

Diyelim ki @Jacob, iki klasörüm var: 'Kayıt' ve 'Video'. Her ikisini de kontrol etmelidir. Alt klasörlerden herhangi biri dosyayı içeriyorsa, '635623' klasörü silinmez. Ve ayrıca yapılabilir olup olmadığını kontrol etmek için daha fazla klasör ekleme yeteneği ..
Derek James

11

Kullanılması findve xargs:

find A -type d -name 'Recording' -empty -printf '%h\0' | xargs -0 echo rm -rf

( echodoğru dizinleri tanımladığından emin olduktan sonra kaldırın ). printf '%h\0Bölüm (boş sonlandırılmış) üst dizini basar - arasından man find:

       %h     Leading directories of file's name (all but the last ele‐
              ment).  If the file name contains no slashes (since it is
              in  the  current  directory)  the %h specifier expands to
              ".".

Örn .: verilen

$ tree A
A
├── 312311
│   ├── a.txt
│   ├── b.txt
│   └── Recording
├── 453453
│   ├── a.txt
│   ├── b.txt
│   └── Recording
│       └── a.mp3
└── 566532
    ├── a.txt
    ├── b.txt
    └── Recording

6 directories, 7 files

sonra

$ find A -type d -name 'Recording' -empty -printf '%h\0' | xargs -0 rm -rf
$ 
$ tree A
A
└── 453453
    ├── a.txt
    ├── b.txt
    └── Recording
        └── a.mp3

2 directories, 3 files

A-tipi d-adı 'Kayıt'-boş -yazı '% h \ 0' bul | xargs -0 echo rm -rf Bu sadece "rm -rf" yazıyor VE A-tipi d -adı 'Kayıt' -kötü -yazı '% h \ 0' bul | xargs -0 rm -rf çalışmıyor ... Yanlış bir şey mi yapıyorum ..
Derek James

@DerekJames, A'yı gerçek dizinle değiştirmeniz gerekir.
Jacob Vlijm

OP sayılarla dosya adları verdiğinden , Kayıt adının yerine düzenli bir ifade koymak uygun olur [\d]*mu?
George Udosen

@JacobVlijm: Gerçek dizinle değiştirdim ancak hala yazmıyorum?
Derek James

@DerekJames tuhaf! benim sistemimde çalıştı, ama önce dizine cd unutmuş olabilir? Bekle, önemli değil ...
Jacob Vlijm

3

İşte daha basit bir bash çözümü:

for d in */; do rmdir "$d/Recording" && rm -r "$d"; done

rmdirDizin boş değilse başarısız olur ve başarılı olmadığı sürece yürütülmesini &&önler çünkü çalışır . Glob yalnızca dizinler üzerinde çalıştığınızdan emin olur, böylece diğer dosyalar etkilenmez.rm -rrmdir*/


Akıllı düşünme! +1
Jacob Vlijm
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.