การค้นหาไดเรกทอรีว่าง UNIX


92

ฉันต้องการค้นหาไดเร็กทอรีว่างสำหรับรายการไดเร็กทอรีที่กำหนด บางไดเร็กทอรีมีไดเร็กทอรีอยู่ภายใน

หากไดเรกทอรีภายในว่างเปล่าฉันสามารถพูดได้ว่าไดเรกทอรีหลักว่างเปล่ามิฉะนั้นจะไม่ว่างเปล่า

ฉันจะทดสอบสิ่งนี้ได้อย่างไร?

ตัวอย่างเช่น:

A>A1(file1),A2 this is not empty beacuse of file1
B>B1(no file) this is empty
C>C1,C2 this is empty

2
ฉันคิดว่าคำตอบของ Martin เหมาะสมที่สุดสำหรับที่นี่ คำตอบที่ยอมรับในปัจจุบันเป็นเพียงรหัสเทียมที่ไม่สมบูรณ์
LéoLéopold Hertz 준영

คำตอบ:


34

ตรวจสอบว่าfind <dir> -type fส่งออกอะไรหรือไม่ นี่คือตัวอย่าง:

for dir in A B C; do
    [ -z "`find $dir -type f`" ] && echo "$dir is empty"
done

2
ไม่มันจะไม่ส่งออกไดเร็กทอรีย่อย นั่นคือสิ่งที่-type fมีไว้สำหรับ
Marcelo Cantos

หากมีไฟล์ว่างเปล่าโซลูชันของคุณจะไม่แสดงข้อความ
Yasir Arsanukaev

4
Yasir: ฉันคิดว่าไดเร็กทอรีที่มีไฟล์แผลว่างเปล่าจะไม่ว่างเปล่า นั่นจะไม่ใช่ผลลัพธ์ที่ถูกต้องหรือไม่?
Ukko

2
@akostadinov: ถ้าฉันสร้างไดเร็กทอรีและไฟล์ตามที่ OP - mkdir A B C A/A1 A/A2 B/B1 C/C1 C/C2; touch A/A1/file1- และรันโค้ดในคำตอบของฉันมันจะรายงานว่า B และ C ว่างเปล่าตามที่ OP ต้องการ ดังนั้นคุณจะต้องเจาะจงมากกว่านี้หน่อยว่า "มันเคยชิน"
Marcelo Cantos

1
หากคุณเป็น Noob ทุบตีเหมือนผมตรวจสอบสิ่งที่ -z หมายถึงที่นี่
OmarOthman

261

ขึ้นอยู่กับว่าคุณต้องการทำอะไรกับไดเร็กทอรีว่าง ฉันใช้คำสั่งด้านล่างเมื่อต้องการลบไดเร็กทอรีว่างทั้งหมดภายในทรีพูดtestไดเร็กทอรี

find test -depth -empty -delete

สิ่งหนึ่งที่ควรสังเกตเกี่ยวกับคำสั่งข้างต้นก็คือมันจะลบไฟล์เปล่าออกไปด้วยดังนั้นให้ใช้ตัวเลือก-type dเพื่อหลีกเลี่ยงสิ่งนั้น

find test -depth -type d -empty -delete

วาง-deleteเพื่อดูไฟล์และไดเรกทอรีที่ตรงกัน

หากคำจำกัดความของแผนผังไดเร็กทอรีว่างของคุณคือไม่มีไฟล์คุณจะสามารถรวมบางสิ่งเข้าด้วยกันโดยขึ้นอยู่กับว่าจะfind test -type fส่งคืนอะไรหรือไม่

find เป็นยูทิลิตี้ที่ยอดเยี่ยมและ RTFM ในช่วงต้นและบ่อยครั้งที่จะเข้าใจว่ามันทำได้มากแค่ไหน :-)


8
- ลบหมายถึง -depth (อย่างน้อยสำหรับ GNU findutils 4.4.2)
Dr. Person Person II

4
ไม่รู้เรื่อง-emptyสะดวกจัง!
Raffi

2
อย่างไรก็ตามบนเครื่องที่ไม่ใช่ linux ล่าสุดและยิ่งใหญ่ที่สุด (EG Solaris) แล้วคุณจะไม่มีคุณสมบัติแปลก ๆ เช่น - ว่างเปล่าหรือ - ลบ
anthony

3
บน MacOS-X สำหรับไดเร็กทอรีที่เกือบว่างให้เรียกใช้find test -name ".DS_Store" -deleteก่อนจากนั้นจึงใช้-empty deleteคำสั่ง นอกจากนี้โปรดทราบว่าต้องการไปpushdยังไดเร็กทอรีหลักดังนั้นจึงfind testกลายเป็นfind .แต่คำสั่งที่เหลือจะเหมือนกัน
Olie

1
@Martin คุณช่วยเพิ่มคำจำกัดความของ-depthที่นี่ได้ไหมเช่น สาเหตุค้นหาเพื่อทำการสำรวจเชิงลึกเป็นอันดับแรกกล่าวคือมีการเยี่ยมชมไดเร็กทอรีในลำดับหลังและรายการทั้งหมดในไดเร็กทอรีจะดำเนินการก่อนไดเร็กทอรีเอง ฉันคิดว่ามันมีความเกี่ยวข้องที่นี่
LéoLéopold Hertz

50

คุณสามารถใช้คำสั่งต่อไปนี้:

find . -type d -empty

1
- ว่างจะใช้งานได้ก็ต่อเมื่อไดเร็กทอรีปัจจุบันว่างเปล่าอย่างสมบูรณ์ไม่ใช่หากทรีย่อยไม่มีไฟล์
Marcelo Cantos

@soField ทดสอบค้นหา - พิมพ์ d - ว่างเปล่าด้วย FreeBSD & CentOS ใช้งานได้ดี ระบบปฏิบัติการของคุณคืออะไร?
mosg

1
hp-ux จึงไม่มีพารามิเตอร์ว่าง
soField

@soField เห็นมั้ยว่าดีกว่า (สำหรับพวกเราทุกคน) โพสต์ข้อมูลนี้ไว้ที่ด้านบนของคำถามของคุณ ...
mosg

2
find ไม่มี -empty บน solaris เช่นกัน แต่มี -depth ในการบังคับใช้การข้ามผ่านเชิงลึกก่อนเพื่อให้สามารถลบไดเร็กทอรีย่อยว่างก่อนที่ไดเร็กทอรีหลักจะถูกตรวจสอบความว่างเปล่า
eirikma

26
find directory -mindepth 1 -type d -empty -delete

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

ตัวเลือก mindepth ป้องกันไม่ให้ไดเร็กทอรีถูกลบหากว่างเปล่า


2
คุณสามารถติดตามเรื่องนี้rmdir --ignore-fail-on-non-empty -p directoryเพื่อกำจัดพ่อแม่ได้เช่นกัน
Pete Peterson

@Pete Peterson คำสั่งของฉันดูเหมือนจะลบไดเร็กทอรีที่มีเฉพาะไดเร็กทอรีว่างอื่น ๆ (ซึ่งเป็นสิ่งที่ OP ดูเหมือนจะต้องการ) ฉันทราบว่าคำสั่งของคุณมักจะปล่อยให้ผู้ใช้อยู่ในไดเร็กทอรีพร้อมกับ i-node ที่หายไปแม้ว่าพวกเขาจะบรรลุสิ่งที่ต้องการซึ่งอาจทำให้พวกเขาสับสน บางทีฉันอาจจะพลาด
Dr. Person Person II

23

find . -type d -empty

ค้นหาและแสดงรายการไดเร็กทอรีว่างและไดเร็กทอรีย่อยในแผนผังปัจจุบัน เช่นรายการผลลัพธ์ของ dirs และ subdirs ที่ว่างเปล่า:

./2047
./2032
./2049
./2063
./NRCP26LUCcct1/2039
./NRCP26LUCcct1/2054
./NRCP26LUCcct1/2075
./NRCP26LUCcct1/2070

ไม่มีการดำเนินการบนไดเร็กทอรี มีการระบุไว้อย่างเรียบง่าย สิ่งนี้ใช้ได้กับฉัน


16

เพียงแค่หาไดร์ที่ว่างเปล่า

ในการค้นหาไดเร็กทอรีว่าง (ตามที่ระบุไว้ในหัวข้อคำถาม) คำตอบของ mosgนั้นถูกต้อง:

find -type d -empty

แต่-emptyอาจไม่มีในfindเวอร์ชันเก่ามาก(เช่นกรณีของHP-UX ) หากเป็นกรณีของคุณโปรดดูเทคนิคที่อธิบายไว้ในส่วนด้านล่างไดเรกทอรีว่างเปล่าหรือไม่ .

ลบ dirs ที่ว่างเปล่า

สิ่งนี้ค่อนข้างยุ่งยาก: สมมติว่าไดเร็กทอรีMyDirมีไดเร็กทอรีว่าง หลังจากลบไดเร็กทอรีว่างเหล่านี้แล้วMyDirจะกลายเป็นไดเร็กทอรีว่างและควรลบออกด้วย ดังนั้นฉันจึงใช้คำสั่งrmdirกับตัวเลือก--parents(หรือ-p) ที่ลบไดเร็กทอรีพาเรนต์เมื่อทำได้:

find -type d -empty -exec rmdir -vp --ignore-fail-on-non-empty {} +

ในfindเวอร์ชันที่เก่ากว่า+นั้นยังไม่รองรับคำสั่งดังนั้นคุณสามารถใช้;แทน:

find -type d -empty -exec rmdir -vp --ignore-fail-on-non-empty {} `;`

ไดเรกทอรีว่างเปล่า?

คำตอบเหล่านี้ส่วนใหญ่อธิบายวิธีตรวจสอบว่าไดเร็กทอรีว่างหรือไม่ ดังนั้นฉันจึงให้เทคนิคสามอย่างที่ฉันรู้:

  1. [ $(find your/dir -prune -empty) = your/dir ]

    d=your/dir
    if [ x$(find "$d" -prune -empty) = x"$d" ]
    then
      echo "empty (directory or file)"
    else
      echo "contains files (or does not exist)"
    fi
    

    รูปแบบ:

    d=your/dir
    if [ x$(find "$d" -prune -empty -type d) = x"$d" ]
    then
      echo "empty directory"
    else
      echo "contains files (or does not exist or is not a directory)"
    fi
    

    คำอธิบาย:

    • find -pruneคล้ายกับการfind -maxdepth 0ใช้อักขระน้อย
    • find -type d พิมพ์ไดเร็กทอรีเท่านั้น
    • find -empty พิมพ์ไดเร็กทอรีว่างและไฟล์

      > mkdir -v empty1 empty2 not_empty
      mkdir: created directory 'empty1'
      mkdir: created directory 'empty2'
      mkdir: created directory 'not_empty'
      > touch not_empty/file
      > find empty1 empty2 not_empty -prune -empty
      empty1
      empty2
      
  2. (( ${#files} ))

    เคล็ดลับนี้ 100% bashแต่เรียกใช้ (spawns) เปลือกย่อย แนวคิดนี้มาจากBruno De Fraineและปรับปรุงโดยความคิดเห็นของteambob ฉันแนะนำอันนี้ถ้าคุณใช้ และหากสคริปต์ของคุณไม่จำเป็นต้องพกพา

    files=$(shopt -s nullglob dotglob; echo your/dir/*)
    if (( ${#files} ))
    then 
      echo "contains files"
    else 
      echo "empty (or does not exist or is a file)"
    fi
    

    หมายเหตุ:ไม่มีความแตกต่างระหว่างไดเร็กทอรีว่างและไดเร็กทอรีที่ไม่มีอยู่ (และแม้ว่าพา ธ ที่ให้มาจะเป็นไฟล์ก็ตาม)

  3. [ $(ls -A your/dir) ]

    เคล็ดลับนี้ได้รับแรงบันดาลใจจากบทความของ nixCraft ที่โพสต์ในปี 2550 Andrew Taylorตอบในปี 2008 และgr8can8dianในปี 2011

    if [ "$(ls -A your/dir)" ]
    then
      echo "contains files"
    else
      echo "empty (or does not exist or is a file)"
    fi
    

    หรือเวอร์ชัน bashism บรรทัดเดียว:

    [[ "$(ls -A your/dir)" ]] && echo "contains files" || echo "empty or ..."
    

    หมายเหตุ: lsส่งคืน$?=2เมื่อไม่มีไดเร็กทอรี แต่ไม่มีความแตกต่างระหว่างไฟล์และไดเร็กทอรีว่าง


rmdir -vpช่วยฉันอย่างมากเนื่องจากฉันไม่จำเป็นต้องลบ dirs ว่างทั้งหมดภายใต้รูท แต่ตรวจสอบ dirs และ dirs ผู้ปกครองที่ว่างเปล่าหลังจากลบไฟล์ ในสถานการณ์ของฉัน dirs ว่างนั้นใช้ได้ตราบใดที่พวกเขาไม่ได้อยู่ในแผนภูมิฉันกำลังลบไฟล์ออก ขอบคุณ!
Ethan Hohensee

2

ฟังก์ชันเรียกซ้ำนี้ดูเหมือนจะทำเคล็ดลับ:

# Bash
findempty() {
    find ${1:-.} -mindepth 1 -maxdepth 1 -type d | while read -r dir
    do
        if [[ -z "$(find "$dir" -mindepth 1 -type f)" ]] >/dev/null
        then
            findempty "$dir"
            echo "$dir"
        fi
    done
}

ให้โครงสร้างไดเร็กทอรีตัวอย่างนี้:

    .
    | - dir1 /
    | - dir2 /
    | `- dirB /
    | - dir3 /
    | `- dirC /
    | `- ไฟล์ 5
    | - dir4 /
    | | - dirD /
    | `- ไฟล์ 4
    `- dir5 /
        `- dirE /
            `- dir_V /

ผลลัพธ์ของการเรียกใช้ฟังก์ชันนั้นจะเป็น:

    ./dir1
    ./dir5/dirE/dir_V
    ./dir5/dirE
    ./dir5
    ./dir2/dirB
    ./dir2

/dir4/dirDซึ่งพลาดท่า หากคุณย้ายการเรียกซ้ำfindempty "$dir"หลังจากfiฟังก์ชันฟังก์ชันจะรวมไดเร็กทอรีนั้นไว้ในผลลัพธ์


2

แล้วไงrmdir *? คำสั่งนั้นจะล้มเหลวในไดเรกทอรีที่ไม่ว่างเปล่า


บางครั้งฉันได้ทำบางครั้งเพื่อทำความสะอาดทั่วไป ทำสิ่งต่างๆเช่น rmdir */*/* */* * แม้ว่าจะไม่จัดการ 'dot-files' แต่ในสถานการณ์ด้วยตนเอง (การล้างไฟล์ข้อมูล) โดยทั่วไปคุณไม่คาดหวัง 'dot-files' อย่างไรก็ตามวิธีการเรียกซ้ำใช้สำหรับการล้างข้อมูลทั่วไปโดยอัตโนมัติโดยเฉพาะอย่างยิ่งในโครงสร้างไดเร็กทอรีที่มีขนาดใหญ่มาก
anthony

ในกรณีหนึ่งมีความซับซ้อนมากขึ้นเนื่องจากฉันต้องการลบไดเร็กทอรีว่างที่มีไดเร็กทอรี "ว่าง" รวมอยู่ด้วยซึ่งอาจมีไฟล์ สิ่งอื่นใดในไดเร็กทอรีและมันไม่ 'ว่างเปล่า' ในตัวอย่างนั้นโครงสร้างไดเรกทอรีเกี่ยวข้องกับไดเรกทอรีย่อยหลายหมื่นรายการ
anthony

1

คำสั่งต่อไปนี้จะส่งคืน 1 หากไดเร็กทอรีว่าง (หรือไม่มีอยู่) และ 0 มิฉะนั้น (ดังนั้นจึงเป็นไปได้ที่จะเปลี่ยนโค้ดส่งคืนด้วย!เชลล์สคริปต์):

find $dir -type d -prune -empty -exec false {} +

0

ฉันสร้างโครงสร้างง่ายๆดังนี้:

test/
test/test2/
test/test2/test2.2/
test/test3/
test/test3/file

test/test3/fileมีข้อความขยะบางส่วน

การfind test -emptyส่งคืน " test/test2/test2.2" เป็นไดเร็กทอรีว่างเพียงรายการเดียว


op ขอให้ส่ง test / test2 ด้วย

แน่นอน. แต่ฉันคิดว่าเขาสามารถอ่านหน้าค้นหาคนเพื่อไปต่อได้ สคริปต์ที่ปรับความลึกตามผลลัพธ์จะใช้ได้ดี
James Sumners

นี่เป็นเวอร์ชันที่มีประโยชน์ที่สุดสำหรับการใช้งานของฉันขอบคุณ
Andreas


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