เหตุใด 'grep -q' จึงใช้ไฟล์อินพุตทั้งหมด


23

พิจารณาไฟล์อินพุตต่อไปนี้:

1
2
3
4

วิ่ง

{ grep -q 2; cat; } < infile

ไม่พิมพ์อะไรเลย ฉันคาดว่าจะพิมพ์

3
4

ฉันสามารถรับผลลัพธ์ที่คาดหวังได้หากเปลี่ยนเป็น

{ sed -n 2q; cat; } < infile

เหตุใดคำสั่งแรกไม่พิมพ์ผลลัพธ์ที่ต้องการ
มันเป็นไฟล์อินพุตที่หาได้และเป็นไปตามมาตรฐานภายใต้OPTIONS :

-q
      Quiet. Nothing shall be written to the standard output, regardless of 
      matching lines. Exit with zero status if an input line is selected.

และเพิ่มเติมลงไปภายใต้การใช้งานแอปพลิเคชัน (เน้นการเน้นของฉัน):

-qตัวเลือกให้หมายถึงการได้อย่างง่ายดายกำหนดหรือไม่รูปแบบ (หรือสตริง) ที่มีอยู่ในกลุ่มของไฟล์ เมื่อทำการค้นหาหลาย ๆ ไฟล์มันให้การปรับปรุงประสิทธิภาพ ( เพราะมันสามารถออกได้ทันทีที่พบคู่แรก ) [... ]

ตอนนี้ตามมาตรฐานเดียวกัน (ในบทนำภายใต้ไฟล์ INPUT )

เมื่อสาธารณูปโภคมาตรฐานอ่านแฟ้มใส่ seekable และสิ้นสุดลงโดยไม่ต้องมีข้อผิดพลาดก่อนที่จะถึงจุดสิ้นสุดของแฟ้ม, ยูทิลิตี้ต้องมั่นใจว่าไฟล์ชดเชยในรายละเอียดไฟล์ที่เปิดอยู่ในตำแหน่งที่ถูกต้องเพียงอดีตไบต์ที่ผ่านมาประมวลผลโดยยูทิลิตี้ [ .. ]

tail -n +2 file
(sed -n 1q; cat) < file
...

คำสั่งที่สองเทียบเท่ากับคำสั่งแรกก็ต่อเมื่อสามารถค้นหาไฟล์ได้


เหตุใดจึงgrep -qใช้ไฟล์ทั้งหมด?


นี่คือgnu grepถ้ามันเป็นเรื่องสำคัญ (แม้ว่าKusalanandaเพิ่งยืนยันว่าเกิดขึ้นเดียวกันใน OpenBSD)


OpenBSD's grepเป็นทางแยกของสิ่งที่เรียกว่าFreeGrepหากใครสงสัย
Kusalananda

คำตอบ:


37

grep หยุดเร็ว แต่จะบัฟเฟอร์อินพุตดังนั้นการทดสอบของคุณสั้นเกินไป (และใช่ฉันรู้ว่าการทดสอบของฉันไม่สมบูรณ์เนื่องจากไม่สามารถหาได้):

seq 1 10000 | (grep -q 2; cat)

เริ่มที่ 6776 ในระบบของฉัน ที่ตรงกับบัฟเฟอร์ 32KiB ที่ใช้โดยค่าเริ่มต้นใน GNU grep:

seq 1 6775 | wc

เอาท์พุท

   6775    6775   32768

โปรดทราบว่า POSIX กล่าวถึงการปรับปรุงประสิทธิภาพเท่านั้น

เมื่อค้นหาหลายไฟล์

ไม่ได้ตั้งค่าความคาดหวังใด ๆ สำหรับการปรับปรุงประสิทธิภาพเนื่องจากการอ่านไฟล์เพียงบางส่วน


2

เห็นได้ชัดว่าเป็นเพราะการบัฟเฟอร์ที่grepจะเร่งความเร็วของสิ่งต่าง ๆ มีเครื่องมือที่ออกแบบมาเป็นพิเศษเพื่ออ่านตัวละครได้มากเท่าที่ต้องการและไม่มีอีกต่อไป หนึ่งในนั้นคือexpect:

{ expect -c "log_user 0; expect 2"; cat; } < infile

ฉันไม่มีระบบที่จะลองทำสิ่งนี้ แต่ฉันเชื่อว่าexpectจะกินหมดทุกอย่างจนกว่าจะพบกับสตริงที่คาดหวัง ( 2) จากนั้นจึงยุติและปล่อยให้อินพุตที่เหลือcatอยู่


1

คุณกำลังสับสนและ grep

สำหรับคำสั่ง sed -2qกำลังบอกว่าจะออกจากการวนซ้ำปัจจุบันหากที่บรรทัดที่สอง-nตัวเลือกกำลังบอกว่าจะทำงานอย่างเงียบ ๆ ดังนั้นคุณจะได้รับทุกบรรทัดหลังจากที่ 2

คำสั่ง grep รันตามค่าเริ่มต้นเพื่อส่งออกบรรทัดที่ตรงกันทั้งหมด - แต่-qตัวเลือกบอกว่าจะไม่ส่งออกอะไรไปยัง stdout ดังนั้นหากอินพุตมี "2" จะมีค่าการออกเป็น SUCCESS มิฉะนั้น FAILURE สิ่งเหล่านั้นขึ้นอยู่กับระบบปฏิบัติการและเชลล์ของคุณ ดังนั้นโดยทั่วไปคุณจะบอกได้ว่ามีการจับคู่บรรทัดหรือไม่โดยตรวจสอบค่าการออกของกระบวนการ grep สิ่งนี้มีประโยชน์ในไปป์ไลน์ที่คุณต้องการทราบว่าอินพุตของคุณมีค่าบางอย่างเป็นการทดสอบ เช่น

if grep -q 'crash' <somelog.log ; then report_crash_via_email ; fi

ในกรณีนี้เราไม่สนใจที่จะเห็นเส้นที่ตรงกันทั้งหมดเราแค่สนใจว่ามีอย่างน้อยหนึ่งบรรทัด report_crash_via_emailกระบวนการ / ฟังก์ชั่นนั้นอาจจะไปปิดและเปิดไฟล์หรือไม่

หากคุณต้องการให้กระบวนการ grep ของคุณหยุดทำงานหลังจากพบอักขระ "2" - จะไม่เป็นค่าเริ่มต้นมันจะตรวจสอบทุกบรรทัดที่ค้นหาเพื่อดูว่าตรงกันหรือไม่ - คุณต้องแจ้งให้ทำเช่นนั้น -m <value>สวิตช์บรรทัดคำสั่งที่เป็น grep -q -m1 2ดังนั้นสำหรับกรณีของคุณ


6
คำตอบของคุณคือข้อมูลที่เป็นประโยชน์สำหรับการใช้งานทั่วไปgrepแต่คำถามนี้ถามเกี่ยวกับสิ่งที่ลึกซึ้งและลึกลับยิ่งขึ้น ดูเหมือนว่าคุณได้อ่านคำถามเร็วเกินไปที่จะเข้าใจพฤติกรรมที่แท้จริงที่ถูกสอบถาม นอกจากนี้ GNU grep ไม่ค้นหาหยุดเมื่อใช้กับ-q(ตามที่ได้รับอนุญาตในการอ้างอิงจากข้อมูลจำเพาะ POSIX) ที่: หน้าคนสำหรับรัฐ GNU grep ว่ามัน“ออก [s] ทันทีที่มีสถานะเป็นศูนย์หากการแข่งขันใด ๆ จะพบ” FWIW ฉันได้แก้ไขคำถามของคุณเพื่อแสดงว่าคุณสามารถจัดรูปแบบโพสต์ในอนาคตได้อย่างไร ยินดีต้อนรับกองแลกเปลี่ยน
Anthony G - ความยุติธรรมสำหรับโมนิก้า

ที่กล่าวว่าคำตอบของ @ user212377 ถูกต้อง: ในกรณีนี้grepจะถูกถามว่ามี '2' อยู่ในไฟล์ไม่มีอะไรมากและไม่น้อยไปกว่านี้ มันไม่ทำงานเหมือนsedและกินบันทึกจนถึงจุดนั้นและปล่อยให้เหลือสำหรับการประมวลผลเพิ่มเติม มันอ่านจนกว่ามันจะรู้ว่ามี '2' หรือว่าไม่มีปิดไฟล์และส่งคืนผลลัพธ์
Keith Davies

grepอันที่จริงแล้วมีเพียง 'สิ้นเปลืองไฟล์ทั้งหมด' (ไม่สนใจข้อควรพิจารณาในการบัฟเฟอร์) หากสตริงการค้นหาไม่ปรากฏในไฟล์ (ซึ่งพิสูจน์ได้โดยการตรวจสอบไฟล์ทั้งหมดเท่านั้น) อะไรก็ตามที่น้อยกว่านั้นการหยุดอ่านไฟล์ไฟล์จะถูกปิดและส่งกลับ SUCCESS
Keith Davies
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.