จะเพิกเฉยต่อชื่อไฟล์บางอย่างโดยใช้ "ค้นหา" ได้อย่างไร


137

หนึ่งในคำสั่ง BASH ที่ฉันโปรดปรานคือ:

find . -name '*.*' -exec grep 'SearchString' {} /dev/null \;

ซึ่งค้นหาเนื้อหาของไฟล์ทั้งหมดที่และด้านล่างของไดเรกทอรีปัจจุบันสำหรับ SearchString ที่ระบุ ในฐานะนักพัฒนาซอฟต์แวร์นี้มีประโยชน์หลายครั้ง

เนื่องจากโครงการปัจจุบันของฉันและโครงสร้างของ codebase ของฉันอย่างไรก็ตามฉันต้องการทำให้คำสั่ง BASH นี้มีความก้าวหน้ายิ่งขึ้นโดยไม่ต้องค้นหาไฟล์ใด ๆ ที่อยู่ในหรือด้านล่างไดเรกทอรีที่มี ".svn" หรือไฟล์ใด ๆ ที่ ลงท้ายด้วย ".html"

หน้า MAN สำหรับการค้นหาชนิดของฉันสับสนว่า ฉันลองใช้ -prune และมันทำให้ฉันมีพฤติกรรมแปลก ๆ ในความพยายามข้ามหน้า. html เท่านั้น (เพื่อเริ่มต้น) ฉันพยายาม:

find . -wholename './*.html' -prune -exec grep 'SearchString' {} /dev/null \;

และไม่ได้รับพฤติกรรมที่ฉันหวังไว้ ฉันคิดว่าฉันอาจพลาดจุด -prune พวกคุณช่วยฉันได้ไหม

ขอบคุณ


1
เพียงแค่ fyi: findไม่ใช่คำสั่ง bash ในตัว แต่เป็นโปรแกรมแยกต่างหาก
WakiMiko

1
คุณสามารถค้นหาไฟล์ภายในด้วยgrep -rl 'SearchString'
emanuele

@emanuele สวัสดียินดีต้อนรับสู่ SuperUser (และเครือข่าย Stack Exchange) นี่เป็นคำถามที่ฉันถามและนั่นได้รับคำตอบเมื่อ 2 1/2 ปีก่อน โดยทั่วไปหากคุณต้องการเพิ่มคำตอบให้กับคำถามโปรดทำเช่นนั้นโดยเลื่อนไปที่ด้านล่างแล้วตอบที่นั่นแทนที่จะแสดงความคิดเห็น เนื่องจากคำถามนี้มีคำตอบที่ยอมรับแล้ว (คำถามที่มีเครื่องหมายถูกสีเขียว) จึงไม่น่าเป็นไปได้ที่คำตอบของคุณจะได้รับความสนใจมาก FYI
โคดี้ S

1
สวัสดีมันไม่ได้เป็นคำตอบสำหรับคำถามของคุณ มันเป็นเพียงเคล็ดลับตามที่คุณระบุไว้ในคำนำที่ใช้findในการค้นหาภายในไฟล์
emanuele

2
FWIW -name '*.*'ไม่พบไฟล์ทั้งหมด : เฉพาะไฟล์ที่มี.ชื่อ (การใช้งาน*.*โดยทั่วไปคือ DOS-ism ในขณะที่ใน Unix คุณใช้งานได้ตามปกติ*) find . -exec ...จริงๆตรงกับพวกเขาทั้งหมดเพียงลบอาร์กิวเมนต์ทั้งหมด: หรือถ้าคุณต้องการใช้ grep กับไฟล์ (และข้ามไดเรกทอรี) find . -type f -exec ...เท่านั้นให้ทำ
สเตฟาน

คำตอบ:


189

คุณสามารถใช้คุณสมบัติ negate (!) ของ find เพื่อไม่จับคู่ไฟล์ที่มีชื่อเฉพาะ:

find . ! -name '*.html' ! -path '*.svn*' -exec grep 'SearchString' {} /dev/null \;

ดังนั้นหากชื่อลงท้ายด้วย. html หรือมี. svn ที่ใดก็ได้ในเส้นทางชื่อนั้นจะไม่ตรงกันและดังนั้น exec จะไม่ถูกดำเนินการ


1
ฉันควรจะยังคงระบุ -name ' ที่ไหนสักแห่งในนั้น ฉันจะทำก่อนหรือหลังการถูกปฏิเสธ?
โคดี้ S

ความตั้งใจของคุณในการ*.*จับคู่เพื่อให้แน่ใจว่าตรงกับไฟล์ที่มี.? การค้นหาจะจับคู่ไฟล์ทั้งหมดโดยไม่มีnameคำสั่งดังนั้นข้อมูลด้านบนจะตรงกับทุกอย่างยกเว้น html และ svn
Paul

5
ฉันคิดว่าคุณต้องการมากกว่า-wholename '*.svn*' -name
fuenfundachtzig

2
ใช่มันทำเพื่อที่.svnไดเรกทอรีจะถูกแยกออกจากผลการค้นหา
fuenfundachtzig

1
@Noumenon ! -name '.'ควรแยก.ออกจากผลลัพธ์การค้นหา
พอล

10

ฉันมีปัญหาเดียวกันมานานและมีวิธีแก้ปัญหาหลายอย่างที่สามารถใช้งานได้ในสถานการณ์ที่แตกต่างกัน:

  • ack-grepเป็นประเภทของ "นักพัฒนาgrep" ซึ่งโดยปกติแล้วจะข้ามไดเรกทอรีควบคุมเวอร์ชันและไฟล์ชั่วคราว manหน้าอธิบายถึงวิธีการค้นหาเฉพาะประเภทไฟล์ที่ระบุและวิธีการที่กำหนดของคุณเอง
  • grepของตัวเอง--excludeและ--exclude-dirตัวเลือกสามารถใช้ง่ายมากในการข้ามไฟล์globsและไดเรกทอรีเดียว (ไม่กลมสำหรับไดเรกทอรีโชคไม่ดี)
  • find . \( -type d -name '.svn' -o -type f -name '*.html' \) -prune -o -print0 | xargs -0 grep ... ควรใช้งานได้ แต่ตัวเลือกข้างต้นอาจเป็นเรื่องยุ่งยากน้อยในระยะยาว

8

ต่อไปนี้findคำสั่งไม่ไดเรกทอรีพรุนที่มีชื่อประกอบด้วย .svn , แม้ว่าจะไม่ได้ลงในไดเรกทอรีชื่อเส้นทางตัดจะถูกพิมพ์ ... ( -name '*.svn'เป็นสาเหตุ!) ..

คุณสามารถกรองชื่อไดเรกทอรีผ่าน: grep -d skipซึ่งข้ามเงียบ ๆ "ไดเรกทอรีชื่อ" การป้อนข้อมูลดังกล่าว

ด้วย GNU grep คุณสามารถใช้แทน-H /dev/nullในฐานะที่เป็นปัญหาเล็กน้อย: \+สามารถเร็วกว่า\;เช่น 1 ล้านไฟล์หนึ่งบรรทัดโดยใช้\;มันเอา4m20sใช้\+มันใช้เวลาเพียง1.2s

วิธีการต่อไปนี้ใช้xargsแทน-execและถือว่าไม่มีการขึ้นบรรทัดใหม่\nในใด ๆ ของไฟล์ของคุณชื่อ ในฐานะที่ใช้ที่นี่เป็นมากเช่นเดียวกับหาของ xargs\+

xargsสามารถส่งชื่อไฟล์ที่มีช่องว่างติดกันโดยการเปลี่ยนตัวคั่นอินพุต'\n'ด้วย-dตัวเลือก

นี้ไม่รวมไดเรกทอรีที่มีชื่อประกอบด้วย .svnและ greps .htmlเฉพาะไฟล์ที่ไม่ได้จบลงด้วย

find . \( -name '*.svn*' -prune  -o ! -name '*.html' \) |
   xargs -d '\n' grep -Hd skip 'SearchString'

1
ขอบคุณสำหรับการชี้ให้เห็นความ\+แตกต่างของการดำเนินการ -exec ไชโยสำหรับปัญหาด้านเล็กน้อย!
Christian Long

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