ลบไฟล์ทั้งหมดยกเว้นในไดเรกทอรีย่อยที่แน่นอนด้วยการค้นหา


11

ฉันต้องการที่จะซ้ำลบไฟล์ทั้งหมดไม่สามารถเข้าถึงในขณะที่อยู่ในโฟลเดอร์ยกเว้นไฟล์ทั้งหมดในโฟลเดอร์ย่อยab

find a \( -name b -prune \) -o -type f -delete

อย่างไรก็ตามฉันได้รับข้อความแสดงข้อผิดพลาด:

ค้นหา: การกระทำ -delete เปิดโดยอัตโนมัติ -depth แต่ -prune ไม่ทำอะไรเลยเมื่อ -depth มีผล หากคุณต้องการดำเนินการต่อให้ใช้ตัวเลือก -depth อย่างชัดเจน

การเพิ่ม-depthทำให้ไฟล์ทั้งหมดbรวมอยู่ด้วยซึ่งจะต้องไม่เกิดขึ้น

ใครรู้วิธีที่ปลอดภัยในการทำงานนี้


@ MichaelKjörling: ฉันได้ดู extglob แต่คุณจะรวมทุกอย่างภายใต้aยกเว้นa/bอย่างไร
comerin

จะไม่cd a && ls -d !(b/*)ทำงานเหรอ (ต้องการทำrm -rมากกว่าเพียงls -d)
CVn

ข้อเสนอแนะของคุณลบโฟลเดอร์ย่อย ฉันต้องการเก็บโฟลเดอร์ไว้เหมือนเดิม ฉันต้องการค้นหาและลบไฟล์ทั้งหมดในทรีภายใต้a(ยกเว้นไฟล์ใต้a/b)
comerin

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

@ MichaelKjörlingเพียงเพราะทั้งสองปัญหามีวิธีแก้ไขปัญหาที่คล้ายคลึงกันไม่ได้ทำให้คำถามซ้ำซ้อน การแก้ปัญหาส่วนใหญ่สำหรับปัญหาทั้งสองไม่ได้แก้ปัญหาอื่น
Gilles 'หยุดชั่วร้าย'

คำตอบ:


13

TL; DR: วิธีที่ดีที่สุดคือการใช้แทน-exec rm-delete

find a \( -name b -prune \) -o -type f -exec rm {} +

คำอธิบาย:

ทำไมถึงพบบ่นเมื่อคุณพยายามที่จะใช้-deleteกับ-prune?

คำตอบสั้น ๆ : เพราะ-deleteหมายถึง-depthและ-depthทำให้-pruneไม่มีประสิทธิภาพ

ก่อนที่เราจะมาถึงคำตอบที่ยาวนานก่อนอื่นให้สังเกตพฤติกรรมของการค้นหาที่มีและไม่มี-depth:

$ find foo/
foo/
foo/f1
foo/bar
foo/bar/b2
foo/bar/b1
foo/f2

ไม่มีการรับประกันเกี่ยวกับการสั่งซื้อในไดเรกทอรีเดียว แต่มีการรับประกันว่าไดเรกทอรีจะถูกประมวลผลก่อนเนื้อหา หมายเหตุfoo/ก่อนfoo/*และก่อนที่จะfoo/barfoo/bar/*

-depthนี้สามารถกลับด้วย

$ find foo/ -depth
foo/f2
foo/bar/b2
foo/bar/b1
foo/bar
foo/f1
foo/

โปรดทราบว่าตอนนี้สิ่งที่ปรากฏก่อนfoo/* เช่นเดียวกันกับfoo/foo/bar

คำตอบอีกต่อไป:

  • -pruneป้องกันการค้นหาจากมากไปน้อยในไดเรกทอรี ในคำอื่น ๆ-pruneข้ามเนื้อหาของไดเรกทอรี ในกรณีของคุณ-name b -pruneป้องกันหาได้จากมากไปหาน้อยลงในไดเรกทอรีใด ๆ bที่มีชื่อ
  • -depthทำให้ค้นหาเพื่อประมวลผลเนื้อหาของไดเรกทอรีก่อนไดเรกทอรีเอง ซึ่งหมายความว่าเมื่อถึงเวลาที่ได้รับการประมวลผลรายการไดเรกทอรีbเนื้อหาที่ได้รับการประมวลผลแล้ว ดังนั้นจึง-pruneไม่ได้-depthผล
  • -deleteแสดงนัย-depthเพื่อให้สามารถลบไฟล์ก่อนแล้วจึงไปยังไดเรกทอรีว่าง -deleteปฏิเสธที่จะลบไดเรกทอรีที่ไม่ว่างเปล่า ผมคิดว่ามันจะเป็นไปได้ที่จะเพิ่มตัวเลือกที่จะบังคับให้-deleteลบไดเรกทอรีที่ไม่ว่างเปล่าและ / หรือเพื่อป้องกันการที่จะบ่งบอก-delete -depthแต่นั่นเป็นอีกเรื่องหนึ่ง

มีวิธีอื่นในการบรรลุสิ่งที่คุณต้องการ:

find a -not -path "*/b*" -type f -delete

สิ่งนี้อาจจะใช่หรือไม่ใช่จดจำได้ง่ายกว่า

คำสั่งนี้ยังคงสืบทอดไปยังไดเรกทอรีbและประมวลผลทุกไฟล์ในนั้นเพียง-notเพื่อปฏิเสธพวกเขา นี่อาจเป็นปัญหาด้านประสิทธิภาพหากไดเรกทอรีbมีขนาดใหญ่

-path-nameการทำงานที่แตกต่างกว่า -nameจับคู่กับชื่อ (ของไฟล์หรือไดเรกทอรี) เท่านั้นขณะที่-pathจับคู่กับพา ธ ทั้งหมด /home/lesmana/foo/barยกตัวอย่างเช่นสังเกตเส้นทาง เพราะจะตรงกับชื่อเป็น-name -bar จะจับคู่เพราะสตริงอยู่ในเส้นทาง มีความซับซ้อนที่คุณควรเข้าใจก่อนใช้งาน อ่าน man page ของสำหรับรายละเอียดเพิ่มเติมbar-path "*/foo*"/foo-pathfind

ระวังว่ามันจะไม่ผิดพลาด 100% มีโอกาสของ "การบวกเท็จ" วิธีที่คำสั่งถูกเขียนไว้ด้านบนมันจะข้ามไฟล์ใด ๆ ที่มีไดเรกทอรีหลักที่ชื่อเริ่มต้นด้วยb(บวก) แต่มันจะข้ามไฟล์ใด ๆ ที่ชื่อขึ้นต้นด้วยbโดยไม่คำนึงถึงตำแหน่งในทรี (false positive) "*/b*"นี้สามารถแก้ไขได้โดยการเขียนการแสดงออกที่ดีกว่า ที่เหลือเป็นแบบฝึกหัดสำหรับผู้อ่าน

ฉันคิดว่าคุณใช้aและbเป็นตัวยึดตำแหน่งและชื่อจริงมีลักษณะเหมือนallosaurusและbrachiosaurusมากกว่า หากคุณใส่brachiosaurusในสถานที่ของbแล้วจำนวนบวกเท็จจะลดลงอย่างเห็นได้ชัด

อย่างน้อยผลบวกปลอมจะไม่ถูกลบดังนั้นจึงไม่เป็นเรื่องน่าเศร้า นอกจากนี้คุณสามารถตรวจสอบผลบวกผิดพลาดโดยเรียกใช้คำสั่งแรกโดยไม่ต้อง-delete(แต่อย่าลืมวางนัย-depth) และตรวจสอบผลลัพธ์

find a -not -path "*/b*" -type f -depth

-not -pathเป็นเพียงสิ่ง! ขอบคุณสำหรับคำอธิบายที่ใจดี!
comerin

1
อธิบายรายละเอียดเกี่ยวกับสาเหตุที่-not -pathทำงานในขณะที่-pruneจะไม่เป็นประโยชน์ ทำไมสามารถ-not -pathอยู่ร่วมกับ-depth?
Faheem Mitha

3

เพียงใช้rmแทน-delete:

find a -name b -prune -o -type f -exec rm -f {} +

1
คุณอธิบายรายละเอียดเกี่ยวกับสาเหตุที่ใช้rmงานdeleteได้หรือไม่
Faheem Mitha

1
โอ้ฉันเดาว่าอาจเป็นเพราะ "-delete ปฏิเสธที่จะลบไดเรกทอรีที่ไม่ว่างเปล่า" เพื่ออ้างอิง @lesmana ดังนั้นปฏิเสธที่จะลบไดเรกทอรีที่ไม่ว่างเปล่า แต่rmไม่มีปัญหานั้น แต่ไม่ว่าการทำอย่างประณีตจะเป็นสิ่งที่ดี
Faheem Mitha

@FaheemMitha คำตอบที่อยู่ในคำถาม -deleteหมายถึงซึ่งเห็นได้ชัดว่าไม่สามารถทำงานร่วมกับ-depth ใช้งานได้ แต่ไม่ได้หยุดจากมากไปน้อยในไดเรกทอรีซึ่งไม่จำเป็นต้องสำรวจ -prune-pathfind
Stéphane Chazelas

0

คำตอบและคำอธิบายข้างต้นมีประโยชน์มาก

ฉันใช้วิธีแก้ปัญหาของ "-exec rm {} +" หรือ "-not -path ... -delete 'แต่สิ่งเหล่านี้อาจช้ากว่า" find ... -delete "ฉันเห็น" find ... -delete "รัน 5x เร็วกว่า" -exec rm {} + "บนไดเร็กทอรีระดับลึกบนระบบไฟล์ NFS

โซลูชัน '-not path "มีค่าใช้จ่ายที่ชัดเจนในการดูไฟล์ทั้งหมดในไดเรกทอรีที่แยกออกและด้านล่าง

การเรียก "find .. -exec rm {} +" rm ซึ่งทำการเรียกระบบ:

fstatat(AT_FDCWD, path...); 
unlinkat(AT_FDCWD, path, 0)

"find -delete" ทำการเรียกระบบ:

 fd=open(dir,...);
 fchdir(fd); 
 fstatat(AT_FDCWD, filename,...)
 unlinkat(dirfd, filename,...)

ดังนั้น "-exec rm {} +" rm ทำพา ธ เต็มเพื่อค้นหา inode สองครั้งต่อไฟล์ แต่ "find -delete" จะทำสถิติและยกเลิกการเชื่อมโยงชื่อไฟล์ในไดเรกทอรีปัจจุบัน นั่นเป็นชัยชนะครั้งใหญ่เมื่อคุณลบไฟล์จำนวนมากในไดเรกทอรีเดียว

(เปิดโหมดสะอื้น (ขออภัย))

ดูเหมือนว่าการออกแบบการทำงานร่วมกันระหว่าง -depth, -delete และ -prune นั้นไม่จำเป็นต้องกำจัดวิธีที่มีประสิทธิภาพมากที่สุดในการดำเนินการทั่วไป "ลบไฟล์ยกเว้นที่อยู่ในไดเรกทอรี -prune"

การรวมกันของ "-type f -delete" ควรจะสามารถทำงานได้โดยไม่ต้อง -depth เพราะมันไม่ได้พยายามที่จะลบไดเรกทอรี อีกวิธีหนึ่งถ้า "ค้นหา" มีการดำเนินการ "-deletefile" ที่ระบุว่าห้ามลบไดเร็กทอรี -depth จะไม่จำเป็นต้องบอกเป็นนัย

การเรียกใช้ xargs หรือ find -exec ไปยังคำสั่ง rm อาจถูกเร่งถ้า rm มีตัวเลือกในการเรียงชื่อไฟล์เปิดไดเรกทอรีและยกเลิกการเชื่อมโยง (dir_fd ชื่อไฟล์) แทนการยกเลิกการเชื่อมโยงพา ธ แบบเต็ม มันจะทำการยกเลิกการเชื่อมโยง (dir_fd, ชื่อไฟล์) เมื่อเรียกซ้ำผ่านไดเรกทอรีด้วยตัวเลือก -r

(โหมดปิดเสียงหอน)

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