วิธีการลบไดเรกทอรีตามผลลัพธ์ของ find find?


148

ฉันออกคำสั่งต่อไปนี้เพื่อค้นหาไดเรกทอรี. svn:

find . -name ".svn"

ที่ให้ผลลัพธ์ต่อไปนี้กับฉัน:

./toto/.svn
./toto/titi/.svn
./toto/tata/.svn

ฉันจะประมวลผลบรรทัดทั้งหมดเหล่านี้ด้วยวิธีการrm -frเพื่อลบไดเรกทอรีและเนื้อหาได้อย่างไร


3
GNU find มี-deleteตัวเลือก
Marco

5
หรือคุณสามารถเพิ่ม-exec rm -r "{}" \;ในส่วนท้ายของการค้นหา - ระวังเมื่อใช้rm -r! :)
Drav Sloan

10
@Marco ดูเหมือนว่าตัวเลือกการลบจะไม่ทำงานในไดเรกทอรี
Arnaud

@ SuperChafouin มันทำงานได้อย่างสมบูรณ์แบบดีที่นี่ในไฟล์และไดเรกทอรี ประเด็นก็คือว่ามันจะลบไดเรกทอรี emtpy เท่านั้นและเมื่อคุณระบุ-name ".svn"ตรงกับ.svnไดเรกทอรีเท่านั้นเองและไม่ใช่ไฟล์ที่อยู่ใน.svnไดเรกทอรี
มาร์โก

1
@SuperChafouin แต่จะไม่ทำงานสำหรับเส้นทางที่มีช่องว่างในพวกเขา (จึงใช้-execกับยกมา"{}")
Drav Sloan

คำตอบ:


194

ค้นหาสามารถเรียกใช้อาร์กิวเมนต์ด้วย-execตัวเลือกสำหรับการแข่งขันแต่ละรายการที่พบ มันเป็นกลไกที่แนะนำเพราะคุณสามารถจัดการเส้นทางที่มีช่องว่าง / การขึ้นบรรทัดใหม่และอักขระอื่น ๆ ได้อย่างถูกต้อง คุณจะต้องลบเนื้อหาของไดเรกทอรีก่อนจึงจะสามารถลบไดเรกทอรีได้ดังนั้นให้ใช้-rกับrmคำสั่งเพื่อให้ได้สิ่งนี้

สำหรับตัวอย่างของคุณคุณสามารถออก:

find . -name ".svn" -exec rm -r "{}" \;

นอกจากนี้คุณยังสามารถบอกให้ find ค้นพบไดเรกทอรีที่ชื่อ. svn ด้วยการเพิ่ม-type dเครื่องหมาย:

find . -name ".svn" -type d -exec rm -r "{}" \;

คำเตือนใช้rm -rด้วยความระมัดระวังเพราะจะเป็นการลบโฟลเดอร์และเนื้อหาทั้งหมด

หากคุณต้องการลบเฉพาะไดเรกทอรีที่ว่างเปล่าเช่นเดียวกับไดเรกทอรีที่มีเฉพาะไดเรกทอรีที่ว่างเปล่าค้นหาสามารถทำได้ด้วยตัวเองด้วย-deleteและ-empty:

find . -name ".svn" -type d -empty -delete

21
ฉันได้เห็นคำแนะนำในการเรียกใช้เสมอ-type หลังจาก -nameคำสั่งในการค้นหาเนื่องจากโทรไปstatที่จะได้รับชนิดที่มีราคาแพง ฉันแค่ลองเองด้วยไฟล์ที่มีขนาดใหญ่พอสมควรและดูเหมือนว่าจะเป็นจริง: การทำงานใช้find . -name 'foo' -type dเวลา 19 วินาทีในขณะที่find . -type d -name 'foo'ใช้เวลา 32 วินาที ดังนั้นใช้เวลานานกว่า 50% ในการรัน-typeครั้งแรก
spinup

6
ฉันใช้คำสั่งนี้มาหลายปีแล้ว แต่สำหรับ Mac ตอนนี้ฉันได้รับข้อผิดพลาดที่บอกว่าไม่มีไดเรกทอรีเหล่านั้น แม้ว่ามันจะลบพวกเขา ฉันไม่เคยเห็นข้อความมาก่อน
chovy

1
เหมือนกับ @chovy มีวิธีกำจัดข้อความเหล่านี้หรือไม่?
Clément

2
@chovy @ clémentนั่นเป็นเพราะfindต้องการที่จะเห็นในโฟลเดอร์นั้นสำหรับการแข่งขันอื่น ๆ ในขณะที่มันลบโฟลเดอร์ในเวลาเดียวกัน ~ ฉันยังไม่รู้วิธีแก้ไขปัญหานี้ ~ การแก้ไขที่สกปรก:find . -name "folder-to-delete" -print0 | xargs -r0 -- rm -r
Charlie

5
@chovy @ Clémentฉันคิดว่า-depthข้อโต้แย้งนี้จะแก้ไข:find . -depth -name ".svn" -type d -exec rm -r "{}" \;
gimboland

67

นี่คืออุปกรณ์พกพาที่เร็วกว่าวิธีตอบรับที่ยอมรับได้

การใช้+เซมิโคลอนแทนการใช้findคำสั่งเทอร์มินัลคือการปรับการใช้ CPU ให้เหมาะสม อาจมีความสำคัญหากคุณมี.svnไดเรกทอรีย่อยมากมาย:

find . -name .svn -type d -exec rm -rf {} +

ยังทราบว่าคุณไม่1จำเป็นต้องพูดวงเล็บปีกกาที่นี่

1ยกเว้นว่าคุณใช้fishเปลือก


5
ความแตกต่างระหว่าง + และเครื่องหมายอัฒภาคคืออะไร ทำไมเราไม่ใช้เครื่องมือจัดฟันแบบหยิก
Shicheng Guo

1
@ShichengGuo ด้วยเครื่องหมายอัฒภาคจะมีหนึ่งคำสั่ง rm ต่อไดเรกทอรีที่พบด้วย + คำสั่ง rm เดียวจะประมวลผลไดเรกทอรีทั้งหมดที่พบ (หรืออย่างน้อยจำนวนมากของพวกเขา) ฉันไม่ได้รับคำถามที่สองของคุณหยิก เครื่องมือจัดฟันถูกใช้ที่นี่
jlliagre

ฉันคิดว่า @ShichengGuo หมายความว่าทำไมเราไม่จำเป็นต้องพูดวงเล็บปีกกาที่นี่ (@jlliagre เขียนว่าเราไม่จำเป็นต้องอ้างพวกเขา) ฉันไม่สามารถหาข้อมูลอ้างอิงได้ในตอนนี้ แต่ฉันเข้าใจว่าเป็นเพราะการค้นหาจะยกเว้นเส้นทางที่ถูกแทนที่ด้วย {} โดยอัตโนมัติ
Quinn Comendant

คำตอบและคำถามนั้นค่อนข้างไม่ถูกต้องในสิ่งที่ + ทำ หากพบไฟล์จำนวนมาก ';' จะให้ข้อผิดพลาด 'บรรทัดคำสั่งยาวเกินไป' + แยกไฟล์ที่พบในแบตช์ซึ่งน้อยกว่าความยาวบรรทัดคำสั่งสูงสุดที่อนุญาตและเรียกใช้คำสั่งสำหรับแต่ละแบทช์
gaoithe

1
@gaoithe ฉันย้อนกลับไปคุณแก้ไขซึ่งแทนที่คำสั่งที่ถูกต้องด้วยคำสั่งที่ไม่ถูกต้อง การใช้+ จะลดการใช้งาน CPU การใช้; ไม่ทำให้เกิดข้อผิดพลาดนานเกินไป
jlliagre

27

สมมติว่าคุณใช้gnu findคุณสามารถใช้-deleteตัวเลือก:

find . -name test -delete

ซึ่งง่ายต่อการจดจำ


ลองขยายโพสต์ของคุณด้วยคำอธิบายของคำสั่ง (หรือเอกสารประกอบเพื่อสำรองโซลูชันของคุณ) บ่อยครั้งที่หนึ่ง (หรือสอง) คำตอบของบรรทัดไม่สว่างมากที่สุด
HalosGhost

94
สิ่งนี้ใช้ไม่ได้กับไดเรกทอรีที่ไม่ว่างเปล่า
belacqua

2
ยังทำงานบน Mac OS X
วาด

สิ่งนี้ใช้ไม่ได้กับโฟลเดอร์ที่ไม่ว่างเปล่า แต่เป็นวิธีที่ง่ายและปลอดภัยกว่า
RousseauAlexandre

คำสั่งออปชั่นมีความสำคัญมากค้นหาจะดำเนินการตามลำดับดังนั้น - เดลจะต้องเป็นรายการสุดท้าย
Jose Ignacio Centeno

13

บนคอมพิวเตอร์ของฉันเมื่อฉันใช้:

find . \( -name dirname -type d \) -exec rm -r '{}' ';'

ไดเรกทอรีจะถูกลบ แต่ฉันได้รับข้อผิดพลาด:

find: ‘./dirname’: No such file or directory

สำหรับแต่ละไดเรกทอรี

ไดเรกทอรีของฉันไม่ว่างดังนั้นตัวเลือก -delete จะไม่ทำงานสำหรับฉัน ฉันพบสาเหตุของพฤติกรรมนี้ที่นี่ :

  1. find takes (ไม่จำเป็น) รายการแรกในไดเร็กทอรี. / นี้จะเป็นเช่น dir.1 /
  2. มันเปรียบเทียบกับรูปแบบ 'dir.' มันตรงกับ? ใช่.
  3. ค้นหาเรียกใช้งาน "rm -r dir.1"
  4. find พยายามป้อน dir.1 / เพื่อค้นหารูปแบบภายในไดเร็กทอรี มันไม่รู้อะไรเลยเกี่ยวกับคำสั่ง exec
  5. ไม่พบ dir.1 / อีกต่อไป ส่งกลับ ENOENT (ดูที่เอาต์พุต strace)

ฉันใช้สิ่งนี้แทนเพื่อหลีกเลี่ยง:

rm -r `find . -name dirname -type d`

โปรดจำไว้ว่าการค้นหาจะยังคงพยายามลดจำนวนลงในไดเรกทอรีที่ชื่อ dirname ซึ่งไม่จำเป็นจริงๆและจะต้องใช้เวลาเพิ่มเติม คุณอาจสามารถแก้ไขปัญหานี้ได้ด้วย--depthตัวเลือกการค้นหาทั้งนี้ขึ้นอยู่กับโครงสร้างไดเรกทอรีของคุณ นอกจากนี้หากคุณมีโครงสร้างไดเรกทอรีเช่น dirname / foo / dirname คุณจะได้รับข้อผิดพลาด "ไม่มีไฟล์หรือไดเรกทอรีดังกล่าว" จาก rm เพื่อระงับข้อผิดพลาดคุณสามารถเปลี่ยนเส้นทาง stderr ไปยัง / dev / null หรือใช้การ-fตั้งค่าสถานะ (บังคับ) ด้วย rm


2
ความคิดที่ไม่ดี: ชื่อไฟล์ที่มีช่องว่างจะทำให้เกิดปัญหาที่น่ากลัวทุกประเภท
Clément

2
สำหรับผู้อ่านในอนาคต: find . -name "to-delete" -print0 | xargs -r0 -- rm -rเป็นรุ่นที่ล้มเหลวซึ่งไม่ผิดพลาดในที่ว่าง
Charlie

3
ดูunix.stackexchange.com/a/115869/8257-pruneคุณจะต้องเพิ่ม
Mapio

1
เพิ่ม-pruneเพื่อหลีกเลี่ยงข้อผิดพลาด "ไม่มีไฟล์หรือไดเรกทอรีดังกล่าว"
Julien Carsique

12

วิธีที่เร็วกว่าในการทำเช่นนี้คือ:

find . -name ".svn" -type d -prune -exec rm -rf '{}' '+'

ในกรณีที่คุณมี ".svn" อยู่ในอีกรายการ ".svn"


ไม่มีประโยชน์หากคุณต้องการค้นหาไดเรกทอรีที่จะลบด้วยไดเรกทอรีย่อย
Alexis Wilke

5

วิธีการแก้ปัญหาเฉพาะทุบตี:

shopt -s globstar
rm -r **/.svn
shopt -u globstar #optional. this will disable globstar expansion

3
หมายเหตุสำหรับการขยายบรรทัดคำสั่งของ globs ที่ตรงกับไฟล์จำนวนมากมีการ จำกัด จำนวนไฟล์ที่คุณสามารถจับคู่กับกลไกนี้ การไปเกินขีด จำกัด นี้จะส่งผลให้bash: /bin/rm: Argument list too long
Drav Sloan

1
@DravSloan ถูกต้อง แต่ข้อ จำกัด นั้นอยู่ในไฟล์หลายแสนไฟล์ เป็นสิ่งที่ต้องคำนึงถึง แต่อาจจะไม่เป็นปัญหาสำหรับคนส่วนใหญ่
evilsoup

4

ฉันพบว่าการ-deleteกระทำนั้นทำงานได้ดีกับการ-pathทดสอบ ตัวอย่างเช่นสิ่งต่อไปนี้ควรแก้ไขปัญหาโปสเตอร์ต้นฉบับ:

find . -path '*/.svn*' -delete

คุณแน่ใจไหม? -deleteแสดงถึง-depthและแน่ใจว่าลบไดเรกทอรีที่ไม่ว่างในระบบของฉัน
แมกนัส

ทดสอบซ้ำและใช้งานได้ บางทีมันเป็นแค่คำผิดที่ฉันแก้ไข
kenorb

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