ลบไดเร็กทอรีพาเรนต์ (ไม่ว่าง) หากไดเร็กทอรีย่อยที่ระบุว่างเปล่า


11

ฉันต้องเก็บไดเรกทอรีทั้งหมดที่มีไฟล์ในไดเรกทอรีย่อยที่เฉพาะเจาะจง แต่เพื่อลบส่วนที่เหลือทั้งหมดไดเรกทอรีที่ไดเรกทอรีย่อยว่างเปล่า

จะมีความเฉพาะเจาะจงมากขึ้นที่นี่เป็นโครงสร้าง:

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

ไดเรกทอรีย่อยอาจมีหรือไม่มีไฟล์ ดังนั้นฉันต้องลบไดเรกทอรีทั้งหมดเช่น '312311' & '566532' และควรมีเพียง 453453 เท่านั้นที่มีข้อมูลทั้งหมดอยู่ในนั้นเพราะมีไฟล์ในโฟลเดอร์ 'Recording' ซึ่งเป็นไดเรกทอรีเฉพาะสำหรับฉัน

ฉันเห็นโพสต์จำนวนมาก แต่ลิงก์ไปยังชื่อไฟล์เฉพาะจำนวนมาก ความช่วยเหลือใด ๆ จะได้รับการชื่นชมมากเพราะฉันต้องทำหลายครั้งในหนึ่งสัปดาห์


การบันทึกอยู่ในระดับแรกเสมอในไดเรกทอรีหรือไม่ นอกจากนี้: โฟลเดอร์ทั้งหมดในระดับแรกภายในไดเรกทอรีหลักหรือไม่
Jacob Vlijm

A เป็นไดเรกทอรีระดับบนสุดที่ประกอบด้วยไดเรกทอรีที่มีหมายเลข และในไดเรกทอรีที่มีหมายเลขนั้นจะมีโฟลเดอร์ 'Recording' รวมถึงไฟล์ 'txt' บางไฟล์เช่น และใน 'การบันทึก' อาจมีหรือไม่มีไฟล์ ..
4329 Derek James

คุณจะลบรูปภาพข้อความของคุณและวางข้อความจริงลงในคำถามของคุณ รูปภาพของข้อความยุ่งยากสำหรับเราในการประมวลผล การใช้ข้อความจริงจะสะดวกกว่าในหมู่สิ่งอำนวยความสะดวกอื่น ๆ
LD James

ฉันทำเช่นเดียวกันกับที่คุณถามเจมส์ ..
Derek James

คำตอบ:


12

สคริปต์ด้านล่างจะตรงตามที่คุณอธิบาย:

  1. แสดงรายการโฟลเดอร์ภายในไดเรกทอรี
  2. ดูภายในแต่ละโฟลเดอร์สำหรับโฟลเดอร์ที่ชื่อ "Recording"

    • หากมีอยู่และว่างเปล่าก็จะลบโฟลเดอร์ที่เหนือกว่า
    • ถ้ามันไม่ได้อยู่ก็ยังลบโฟลเดอร์ที่เหนือกว่า
    • ไฟล์ในระดับแรกภายใน A จะไม่ถูกลบ

ในภาพ:

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

จะส่งผลให้:

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

สคริปต์

#!/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

ใช้

  1. คัดลอกสคริปต์ลงในไฟล์เปล่าบันทึกเป็น delete_empty.py
  2. เรียกใช้ด้วยไดเรกทอรี (เต็ม!) (ประกอบด้วยส่วนย่อยของคุณ, ในตัวอย่างของคุณ) เป็นอาร์กิวเมนต์โดยคำสั่ง:

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

แค่นั้นแหละ.

คำอธิบาย

ป้อนเนื้อหาของโฟลเดอร์ "A" ให้กับสคริปต์

os.listdir(dr)

จะแสดงรายการไดเรกทอรีย่อย (และไฟล์) แล้ว:

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

จะพยายามแสดงรายการเนื้อหาของแต่ละโฟลเดอร์ (ย่อย) ซึ่งจะทำให้เกิดข้อผิดพลาดหากรายการนั้นเป็นไฟล์:

except NotADirectoryError
    pass

หรือหากไม่มีโฟลเดอร์ "Recording" อยู่เลย:

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

หากโฟลเดอร์ "Recording" มีอยู่และว่างเปล่าโฟลเดอร์ superior จะถูกลบ:

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

แก้ไข

นอกจากนี้ตามที่ร้องขอในความคิดเห็นเวอร์ชันที่จะตรวจสอบหลายตำบล (ชื่อ)

ในกรณีที่ไดเรกทอรีมีรายการย่อย (ไม่ว่าง) ใด ๆไดเรกทอรีจะถูกเก็บไว้ มิฉะนั้นจะถูกลบ

ใช้

  1. คัดลอกสคริปต์ลงในไฟล์เปล่าบันทึกเป็น delete_empty.py
  2. รันด้วยไดเร็กทอรี (full!) (มี subdirs ของคุณ, ในตัวอย่างของคุณ) และชื่อของ subdirs เป็นอาร์กิวเมนต์โดยคำสั่ง:

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

แค่นั้นแหละ.

สคริปต์

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

บันทึก

โปรดเรียกใช้ในไดเรกทอรีทดสอบก่อนเพื่อให้แน่ใจว่าทำในสิ่งที่คุณต้องการอย่างแน่นอน


รหัสนี้ช่วยได้จริงๆและทำงานได้ตามที่กล่าวไว้ ขอบคุณสำหรับรหัส มีประโยชน์จริงๆ
Derek James

สมมติว่าถ้าฉันต้องการเก็บและตรวจสอบสองโฟลเดอร์หรือมากกว่านั้นฉันจะทำอย่างไรในรหัสนี้? เพิ่ม 'หรือ' หรือไปป์ '| ที่ไหนสักแห่ง .. แนะนำผลรวม!
Derek James

สวัสดี @DerekJames ที่ต้องการการแก้ไขเล็กน้อยฉันจะโพสต์บ่ายนี้
Jacob Vlijm

@Derek รอควรโฟลเดอร์ที่เหนือกว่าถูกลบออกถ้าใด ๆของโฟลเดอร์ที่ว่างเปล่าหรือทั้งหมดหรือไม่ จะมีหลายคนใน dir ที่เหนือกว่าหรือไม่?
Jacob Vlijm

สมมติว่า @Jacob ฉันมีสองโฟลเดอร์ 'การบันทึก' และ 'วิดีโอ' ควรตรวจสอบทั้งสองอย่าง หากโฟลเดอร์ย่อยใด ๆ มีไฟล์อยู่โฟลเดอร์ '635623' จะไม่ถูกลบ และยังเพิ่มความสามารถในการเพิ่มโฟลเดอร์เพื่อตรวจสอบว่าสามารถทำได้หรือไม่ ..
Derek James

11

การใช้findและxargs:

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

(ลบechoทันทีที่คุณสะดวกสบายที่ระบุไดเรกทอรีที่ถูกต้อง) printf '%h\0ส่วนพิมพ์ null (ยกเลิก) ไดเรกทอรีแม่ - จาก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
              ".".

เช่น: ได้รับ

$ 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

แล้วก็

$ 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-type d -name 'Recording' -empty -printf '% h \ 0' | xargs -0 echo rm -rf นี่เป็นเพียงการพิมพ์ "rm -rf" และค้นหา A-type d-name 'Recording' -empty -printf '% h \ 0' | xargs -0 rm -rf ไม่ทำงาน ... ฉันกำลังทำอะไรผิดหรือเปล่า ..
Derek James

@DerekJames คุณต้องแทนที่ A ด้วยไดเรกทอรีจริง
Jacob Vlijm

มันจะตกลงที่จะใส่ในการแสดงผลปกติในสถานที่ของการบันทึกชื่อตั้งแต่ OP ให้ไฟล์ชื่อกับตัวเลขบอก[\d]*?
George Udosen

@JacobVlijm: ฉันแทนที่ด้วยไดเรกทอรีจริง แต่ก็ยังไม่บิด?
Derek James

@DerekJames ที่แปลก! มันทำงานบนระบบของฉัน แต่คุณอาจลืม cd ลงในไดเรกทอรีก่อนหรือไม่ Waitwait ที่ไม่ควรเรื่อง ...
จาค็อบ Vlijm

3

นี่เป็นวิธีทุบตีที่ง่ายกว่า:

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

มันทำงานได้เพราะrmdirจะล้มเหลวหากไดเรกทอรีไม่ว่างเปล่าและ&&จะป้องกันไม่ให้rm -rถูกดำเนินการจนกว่าจะrmdirประสบความสำเร็จ glob */ทำให้แน่ใจว่าคุณกำลังทำงานกับไดเรกทอรีเท่านั้นดังนั้นไฟล์อื่น ๆ จะไม่ได้รับผลกระทบ


คิดอย่างฉลาด! +1
Jacob Vlijm
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.