ลบไดเร็กทอรีขนาดใหญ่ที่มีไฟล์นับพันไฟล์อย่างมีประสิทธิภาพ


159

เรามีปัญหากับโฟลเดอร์ที่ไม่สะดวกกับไฟล์ขนาดเล็กหลายแสนไฟล์

มีไฟล์จำนวนมากที่แสดงrm -rfถึงข้อผิดพลาดและสิ่งที่เราต้องทำมีดังนี้:

find /path/to/folder -name "filenamestart*" -type f -exec rm -f {} \;

ทำงานได้ แต่ช้ามากและล้มเหลวอย่างต่อเนื่องจากหน่วยความจำไม่เพียงพอ

มีวิธีที่ดีกว่าในการทำเช่นนี้? เป็นการดีที่ฉันต้องการลบไดเรกทอรีทั้งหมดโดยไม่สนใจเนื้อหาภายใน


16
rm -rf *ในโฟลเดอร์อาจล้มเหลวเนื่องจากมีอาร์กิวเมนต์มากเกินไป แต่rm -rf folder/ถ้าคุณต้องการลบทั้งไดเรกทอรีออกล่ะ?
sr_

4
แทนที่จะลบมันด้วยตนเองฉันแนะนำให้มีโฟลเดอร์ในพาร์ติชันแยกต่างหาก
bbaja42

7
เพิ่งมาจากความอยากรู้อยากรู้อยากเห็น - มันใช้เวลากี่ไฟล์ในการทำลายrm -rf?
jw013

7
คุณควรเปลี่ยนชื่อคำถามเป็นสิ่งที่แม่นยำยิ่งขึ้นเช่น "ลบไดเรกทอรีขนาดใหญ่ที่มีไฟล์หลายพันไฟล์อย่างมีประสิทธิภาพ" เพื่อที่จะลบไดเรกทอรีและเนื้อหานั้นจำเป็นต้องเรียกซ้ำโดยนิยาม คุณสามารถยกเลิกการลิงก์ด้วยตนเองเพียงไดเรกทอรี inode ตัวเอง (อาจต้องใช้สิทธิ์รูท), ยกเลิกการต่อเชื่อมระบบไฟล์และเรียกใช้fsckเพื่อเรียกคืนบล็อกดิสก์ที่ไม่ได้ใช้ แต่วิธีการดังกล่าวดูมีความเสี่ยงและอาจไม่เร็วขึ้น นอกจากนี้การตรวจสอบระบบไฟล์อาจเกี่ยวข้องกับการสำรวจทรีของระบบไฟล์ซ้ำ ๆ
jw013

4
เมื่อฉันมีccacheต้นไม้ไฟล์ขนาดใหญ่มากและrmใช้เวลานานมาก (และทำให้ทั้งระบบซบเซา) มันเร็วกว่ามากในการคัดลอกไฟล์อื่น ๆ ทั้งหมดออกจากระบบไฟล์รูปแบบและคัดลอกกลับ นับตั้งแต่นั้นฉันให้ขนาดใหญ่ขนาดเล็กต้นไม้ไฟล์เช่นระบบแฟ้มของตนเองโดยเฉพาะเพื่อให้คุณสามารถโดยตรงแทนmkfs rm
frostschutz

คำตอบ:


211

การใช้ rsync นั้นรวดเร็วและง่ายดายอย่างน่าประหลาดใจ

mkdir empty_dir
rsync -a --delete empty_dir/    yourdirectory/

@ คำตอบของ sarath พูดถึงอีกทางเลือกที่รวดเร็ว: Perl! rsync -a --deleteมาตรฐานของมันจะเร็วกว่า

cd yourdirectory
perl -e 'for(<*>){((stat)[9]<(unlink))}'

แหล่งที่มา:

  1. https://stackoverflow.com/questions/1795370/unix-fast-remove-directory-for-cleaning-up-daily-builds
  2. http://www.slashroot.in/which-is-the-fastest-method-to-delete-files-in-linux

4
ขอบคุณมีประโยชน์มาก ฉันใช้ rsync ตลอดเวลาฉันไม่รู้ว่าคุณสามารถใช้มันเพื่อลบแบบนี้ได้ไหม เร็วกว่า rm -rf มาก
John Powell

22
rsyncสามารถเร็วกว่าธรรมดาrmเพราะรับประกันการลบตามลำดับที่ถูกต้องดังนั้นจึงจำเป็นต้องคำนวณค่า btress น้อยลง ดูคำตอบนี้serverfault.com/a/328305/105902
Marki555

7
ทุกคนสามารถแก้ไขการแสดงออก Perl เพื่อลบไดเรกทอรีและไฟล์ทั้งหมดซ้ำภายในdirectory_to_be_deleted ?
Abhinav

5
หมายเหตุ: เพิ่ม-Pตัวเลือกในการ rsync สำหรับการแสดงผลมากขึ้นนอกจากนี้ยังต้องระวังเกี่ยวกับไวยากรณ์ที่ทับต่อท้ายมีผลบังคับใช้ สุดท้ายคุณก็สามารถเริ่มต้นคำสั่ง rsync เป็นครั้งแรกที่มี-nตัวเลือกแรกที่จะเปิดตัวแห้ง
Drasill

1
-aเท่ากับ-rlptgoDแต่สำหรับการลบเท่านั้นที่-rdจำเป็น
โคเอ็น

38

มีคนแนะนำให้ใช้Twitter-deleteแทน-exec rm -f{} \;

สิ่งนี้ได้ปรับปรุงประสิทธิภาพของคำสั่งมันยังคงใช้การเรียกซ้ำเพื่อผ่านทุกสิ่ง


11
นี่ไม่ใช่มาตรฐาน GNU findมี-deleteและอื่น ๆfindอาจจะ
enzotib

13
-deleteควรเลือกใช้-exec rmเมื่อมีเพื่อเหตุผลด้านความปลอดภัยและประสิทธิภาพ
jw013

6
GNU เป็นพฤตินัยมาตรฐาน
RonJohn

17

เกี่ยวกับสิ่งที่ชอบ: find /path/to/folder -name "filenamestart*" -type f -print0 | xargs -0rn 20 rm -f

คุณสามารถ จำกัด -nจำนวนไฟล์ที่ลบในครั้งเดียวโดยการเปลี่ยนอาร์กิวเมนต์สำหรับพารามิเตอร์ ชื่อไฟล์ที่มีช่องว่างรวมอยู่ด้วย


2
คุณอาจไม่ต้องการ-n 20บิตเนื่องจาก xargs ควร จำกัด ตัวเองเป็นขนาดรายการอาร์กิวเมนต์ที่ยอมรับได้
ไร้ประโยชน์

ใช่คุณถูก. นี่คือบันทึกจากman xargs: (...) max-chars characters per command line (...). The largest allowed value is system-dependent, and is calculated as the argument length limit for exec. ดังนั้น-nตัวเลือกสำหรับกรณีดังกล่าวที่ xargs ไม่สามารถกำหนดขนาดบัฟเฟอร์ CLI หรือหากคำสั่งที่ดำเนินการมีข้อ จำกัด บางอย่าง
digital_infinity

12

เคล็ดลับที่ฉลาด:

rsync -a --delete empty/ your_folder/

มันเป็นซีพียูมาก แต่ก็เร็วจริงๆ ดูhttps://web.archive.org/web/20130929001850/http://linuxnote.net/jianingy/en/linux/a-fast-way-to-remove-huge-number-of-files.html


มันไม่เร็วนักเพราะมันจะอ่านเนื้อหาของไดเรกทอรีอย่างมีประสิทธิภาพ ดูคำตอบนี้เพื่อการแก้ปัญหาที่เร็วขึ้น 10 เท่าและคำอธิบายserverfault.com/a/328305/105902
Marki555

2
@ Marki555: ในการแก้ไขของคำถามมีรายงาน 60 วินาทีสำหรับrsync -a --deleteVS lsdent43 อัตราส่วน 10x นั้นสำหรับ time ls -1 | wc -l vs time ./dentls bigfolder >out.txt(นั่นเป็นการเปรียบเทียบที่ยุติธรรมเพียงบางส่วนเนื่องจาก > filevs wc -l)
Hastur

ปัญหามีว่าไม่มีคำสั่งที่นั่นจริงDOการดำเนินการสำรวจเส้นทางที่ต้องการสำหรับการลบ พวกเขาให้รหัส? ไม่ทำงานตามที่อธิบายโดย Marki555
Svartalf

11

จากความคิดเห็นข้อใดข้อหนึ่งฉันไม่คิดว่าคุณกำลังทำสิ่งที่คุณคิดว่าคุณกำลังทำอยู่

ก่อนอื่นฉันสร้างไฟล์จำนวนมากเพื่อจำลองสถานการณ์ของคุณ:

$ mkdir foo
$ cd foo/
$ for X in $(seq 1 1000);do touch {1..1000}_$X; done

จากนั้นฉันลองสิ่งที่ฉันคาดหวังว่าจะล้มเหลวและดูเหมือนว่าคุณกำลังทำอะไรอยู่ในคำถาม:

$ rm -r foo/*
bash: /bin/rm: Argument list too long

แต่นี่ใช้งานได้:

$ rm -r foo/
$ ls foo
ls: cannot access foo: No such file or directory

6
นี่เป็นวิธีเดียวที่ใช้งานได้: เรียกใช้rm -Rf bigdirectoryหลายครั้ง ฉันมีไดเรกทอรีที่มีไดเรกทอรีย่อยและไฟล์หลายพันล้านรายการ ฉันไม่สามารถเรียกใช้lsหรือfindหรือrsyncในไดเรกทอรีนั้นได้เพราะหน่วยความจำไม่เพียงพอ คำสั่งrm -Rfออกจากหลาย ๆ ครั้ง (หน่วยความจำไม่เพียงพอ) เพียงการลบบางส่วนของไฟล์หลายพันล้านไฟล์ แต่หลังจากพยายามหลายครั้งในที่สุดมันก็ทำงาน ดูเหมือนว่าจะเป็นทางออกเดียวถ้าหน่วยความจำไม่เพียงพอเป็นปัญหา
erik

6

ฉันมีโอกาสที่จะทดสอบ-deleteเมื่อเทียบกับ-exec rm \{\} \;และสำหรับฉัน-deleteคือคำตอบของปัญหานี้

ใช้-deleteลบไฟล์ในโฟลเดอร์ 400,000 ไฟล์อย่างน้อย 1,000 rmครั้งเร็วกว่า

บทความ 'วิธีการลบไฟล์จำนวนมากใน linux' แนะนำว่ามันเร็วกว่าสามเท่า แต่ในการทดสอบของฉันความแตกต่างนั้นน่าทึ่งกว่ามาก


3
การใช้คำสั่งfind -execประมวลผลrmสำหรับทุกไฟล์แยกกันจึงเป็นเหตุผลว่าทำไมจึงช้า
Marki555

5

เกี่ยวกับ-deleteตัวเลือกด้านบน: ฉันใช้มันเพื่อลบไฟล์จำนวนมาก (1M + est) ในโฟลเดอร์ temp ที่ฉันสร้างขึ้นและลืมไปทำความสะอาดทุกคืนโดยไม่ตั้งใจ ฉันเติมดิสก์ / พาร์ติชันของฉันโดยไม่ตั้งใจและไม่มีสิ่งอื่นใดสามารถลบออกได้ยกเว้นfind .คำสั่ง ช้าในตอนแรกฉันใช้:

find . -ls -exec rm {} \;

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

find . -delete

แต่ฉันปล่อยให้มันรันทันที ดูเหมือนว่าจะทำงานได้เร็วขึ้นแม้ว่าจะเป็นการเก็บภาษีมากใน CPU ซึ่งคำสั่งอื่นไม่ได้ มันใช้งานมาแล้วประมาณหนึ่งชั่วโมงในตอนนี้และฉันคิดว่าฉันได้รับพื้นที่ว่างบนไดรฟ์และพาร์ทิชันก็ค่อยๆ "ทำตัวให้ผอมลง" แต่มันยังใช้เวลานานมาก ฉันสงสัยอย่างจริงจังว่ามันทำงานเร็วกว่า 1,000 เท่า ในทุกสิ่งฉันต้องการชี้ให้เห็นการแลกเปลี่ยนในอวกาศกับเวลา หากคุณมีแบนด์วิธของ CPU ที่สำรองไว้ (เราทำได้) จากนั้นเรียกใช้งานอันหลัง มันมีซีพียูของฉันทำงานอยู่ ( uptimeรายงาน):

10:59:17 up 539 days, 21:21,  3 users,  load average: 22.98, 24.10, 22.87

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


หากคุณกำลังจะใช้execคุณแทบจะไม่ต้องการใช้-lsและ do find . -type f -exec rm '{}' ++ นั้นเร็วกว่าเพราะมันจะให้อาร์กิวเมนต์จำนวนมากกับ rm อย่างที่มันสามารถจัดการได้ในครั้งเดียว
xenoterracide

ฉันคิดว่าคุณควรไปข้างหน้าและแก้ไขมันเป็นคำตอบของตัวเอง ... มันยาวเกินไปสำหรับความคิดเห็น นอกจากนี้ดูเหมือนว่าระบบไฟล์ของคุณมีการลบค่อนข้างแพงอยากรู้อยากเห็นมันเป็นที่หนึ่ง? คุณสามารถเรียกใช้find … -deleteผ่านniceหรือioniceที่อาจช่วย ดังนั้นอาจเปลี่ยนตัวเลือกการเมานท์บางตัวเป็นการตั้งค่าที่ปลอดภัยน้อยลง (และแน่นอนขึ้นอยู่กับสิ่งอื่นที่อยู่ในระบบไฟล์วิธีที่เร็วที่สุดในการลบทุกอย่างมักจะเป็นmkfs)
Derobert

3
ค่าเฉลี่ยการโหลดไม่ได้เป็น CPU เสมอไปมันเป็นเพียงการวัดจำนวนกระบวนการที่ถูกบล็อกเมื่อเวลาผ่านไป กระบวนการสามารถบล็อกบนดิสก์ I / O ซึ่งน่าจะเป็นสิ่งที่เกิดขึ้นที่นี่
คะแนน _ ต่ำกว่า

โปรดทราบว่าค่าเฉลี่ยการโหลดไม่ได้พิจารณาจำนวนของ CPU แบบโลจิคัล ดังนั้น loadavg 1สำหรับเครื่อง single-core จะเหมือนกับ loadavg 64บนระบบ 64-core - หมายความว่า CPU แต่ละตัวไม่ว่าง 100% ของเวลา
Marki555

3

มีสองสามวิธีที่สามารถใช้เพื่อลบไฟล์จำนวนมากใน linux, คุณสามารถใช้ find with delete ซึ่งเร็วกว่าตัวเลือก exec จากนั้นคุณสามารถใช้การเชื่อมโยง Perl แล้วแม้แต่ rsync วิธีการลบไฟล์จำนวนมากใน linux


3

พิจารณาใช้ปริมาณ Btrfs และเพียงแค่ลบทั้งเล่มสำหรับไดเรกทอรีที่มีไฟล์จำนวนมาก

หรือคุณสามารถสร้างไฟล์ภาพ FS จากนั้นเลิกเมานต์และลบไฟล์เพื่อลบทุกอย่างในครั้งเดียวอย่างรวดเร็ว


2

สมมติว่าparallelติดตั้งGNU ฉันได้ใช้สิ่งนี้:

parallel rm -rf dir/{} ::: `ls -f dir/`

และมันก็เร็วพอ


1

การลบไดเรกทอรีขนาดใหญ่จริงๆต้องการวิธีการที่แตกต่างกันดังที่ฉันได้เรียนรู้จาก เว็บไซต์นี้ - คุณจะต้องใช้ ionice ซึ่งจะทำให้มั่นใจได้ว่า (ด้วย -c3) ว่าการลบจะดำเนินการเฉพาะเมื่อระบบมี IO-time สำหรับมัน โหลดระบบของคุณจะไม่เพิ่มขึ้นสูงและทุกอย่างจะตอบสนอง (แม้ว่าเวลา CPU ของฉันสำหรับการค้นหาค่อนข้างสูงที่ประมาณ 50%)

find <dir> -type f -exec ionice -c3 rm {} \;

5
ใช้+แทน\;จะทำให้มันเร็วขึ้นเพราะมันผ่านการขัดแย้งกันมากขึ้นเพื่อ rm ในครั้งเดียวฟอร์กน้อย
xenoterracide

1
ทำไมไม่ ionice -c3 find <dir> -type f -delete
jtgd

0
ls -1 | xargs rm -rf 

ควรทำงานภายในโฟลเดอร์หลัก


1
lsจะไม่ทำงานเนื่องจากจำนวนไฟล์ในโฟลเดอร์ นี่คือเหตุผลที่ฉันต้องใช้findขอบคุณ
Toby

4
@Toby: ลองls -fซึ่งปิดใช้งานการเรียงลำดับ การเรียงลำดับต้องการให้โหลดไดเรกทอรีทั้งหมดลงในหน่วยความจำเพื่อจัดเรียง สิ่งที่ไม่เรียงลำดับlsควรจะสามารถสตรีมเอาต์พุตได้
camh

1
ไม่ทำงานกับชื่อไฟล์ที่มีการขึ้นบรรทัดใหม่
maxschlepzig

@camh จริง แต่การลบไฟล์ในลำดับที่เรียงนั้นเร็วกว่าที่ไม่เรียงลำดับ (เนื่องจากการคำนวณ btree ของไดเรกทอรีใหม่หลังจากการลบแต่ละครั้ง) ดูคำตอบนี้สำหรับตัวอย่างserverfault.com/a/328305/105902
Marki555

@maxschlepzig สำหรับไฟล์ที่คุณสามารถใช้ได้find . -print0 | xargs -0 rmซึ่งจะใช้ NULL ถ่านเป็นตัวคั่นชื่อไฟล์
Marki555

0

สำหรับคำใบ้ของ Izkata ด้านบน:

แต่นี่ใช้งานได้:

$ rm -r foo/
$ ls foo
ls: cannot access foo: No such file or directory

เกือบจะใช้งานได้หรือจะใช้งานได้ แต่ฉันมีปัญหาในการขออนุญาต มีไฟล์อยู่บนเซิร์ฟเวอร์ แต่ฉันก็ยังไม่เข้าใจว่าปัญหาการอนุญาตนี้มาจากที่ใด อย่างไรก็ตามเทอร์มินัลขอการยืนยันในทุกไฟล์ จำนวนไฟล์อยู่ที่ประมาณ 20,000 ดังนั้นนี่ไม่ใช่ตัวเลือก หลังจาก "-r" ฉันได้เพิ่มตัวเลือก "-f" ดังนั้นคำสั่งทั้งหมดคือ " rm -r -f foldername / " ดูเหมือนว่ามันจะทำงานได้ดี ฉันเป็นมือใหม่ที่มี Terminal แต่ฉันคิดว่ามันก็โอเคใช่มั้ย ขอบคุณ!


0

ฉันแนะนำให้ใช้ทั้งนี้ขึ้นอยู่กับว่าคุณต้องการกำจัดไฟล์เหล่านั้นshredอย่างไร

$ shred -zuv folder

ถ้าคุณต้องการกำจัดไดเรกทอรี แต่คุณไม่สามารถลบมันออกและสร้างมันขึ้นมาใหม่ฉันขอแนะนำให้ย้ายมันและสร้างมันใหม่ทันที

mv folder folder_del
mkdir folder
rm -rf folder_del

เร็วกว่าเชื่อหรือไม่เพราะต้องเปลี่ยนไอโหนดเพียงอันเดียว ข้อควรจำ: คุณไม่สามารถเปรียบเทียบรสชาตินี้กับคอมพิวเตอร์แบบมัลติคอร์ได้ มันมาถึงการเข้าถึงดิสก์ซึ่งถูก จำกัด โดย RAID หรือสิ่งที่มีคุณ


1
shred จะไม่ทำงานกับระบบไฟล์ที่ทันสมัยมากมาย

0

หากคุณมีไฟล์หลายล้านไฟล์และวิธีแก้ไขปัญหาทั้งหมดข้างต้นทำให้ระบบของคุณเกิดปัญหาคุณอาจลองใช้วิธีนี้:

ไฟล์nice_delete:

#!/bin/bash

MAX_LOAD=3
FILES=("$@")
BATCH=100

while [ ${#FILES[@]} -gt 0 ]; do
    DEL=("${FILES[@]:0:$BATCH}")
    ionice -c3 rm "${DEL[@]}"
    echo -n "#"
    FILES=("${FILES[@]:$BATCH}")
    while [[ $(cat /proc/loadavg | awk '{print int($1)}') -gt $MAX_LOAD ]]; do
        echo -n "."
        sleep 1
    done
done

และตอนนี้ลบไฟล์:

find /path/to/folder -type f -exec ./nice_delete {} \+

ค้นหาจะสร้างแบทช์ (ดูgetconf ARG_MAX) nice_deleteของบางส่วนนับพันนับของไฟล์และผ่านมันไป สิ่งนี้จะสร้างแบตช์ที่มีขนาดเล็กลงเพื่อให้หลับเมื่อตรวจพบการโอเวอร์โหลด


0

หากคุณต้องการกำจัดไฟล์จำนวนมากโดยเร็วที่สุดls -f1 /path/to/folder/with/many/files/ | xargs rmอาจใช้งานได้ แต่ดีกว่าอย่ารันบนระบบที่ใช้งานจริงเพราะระบบของคุณอาจมีปัญหา IO และแอปพลิเคชั่นอาจค้างระหว่างการลบ

สคริปต์นี้ทำงานได้ดีกับไฟล์จำนวนมากและไม่ควรส่งผลกระทบต่อ ioload ของระบบ

#!/bin/bash

# Path to folder with many files
FOLDER="/path/to/folder/with/many/files"

# Temporary file to store file names
FILE_FILENAMES="/tmp/filenames"

if [ -z "$FOLDER" ]; then
    echo "Prevented you from deleting everything! Correct your FOLDER variable!"
    exit 1
fi

while true; do
    FILES=$(ls -f1 $FOLDER | wc -l)
    if [ "$FILES" -gt 10000 ]; then
        printf "[%s] %s files found. going on with removing\n" "$(date)" "$FILES"
        # Create new list of files
        ls -f1 $FOLDER | head -n 5002 | tail -n 5000 > "$FILE_FILENAMES"

        if [ -s $FILE_FILENAMES ]; then
            while read FILE; do
                rm "$FOLDER/$FILE"
                sleep 0.005
            done < "$FILE_FILENAMES"
        fi
    else
        printf "[%s] script has finished, almost all files have been deleted" "$(date)"
        break
    fi
    sleep 5
done
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.