grep สำหรับ“ คำศัพท์” และไม่รวม“ คำอื่น”


28

ฉันพยายามสร้างการค้นหา grep ที่ค้นหาคำ แต่ไม่รวมบรรทัดที่มีคำที่สอง ฉันต้องการใช้หลาย-e "pattern"ตัวเลือก แต่ไม่ได้ผล

นี่คือตัวอย่างของคำสั่งที่ฉันลองและข้อความแสดงข้อผิดพลาดที่สร้างขึ้น

grep -i -E "search term" -ev "exclude term"
grep: exclude term: No such file or directory

ฉันเห็นว่ามัน-vใช้ได้กับคำ / รูปแบบการค้นหาทั้งหมด เช่นนี้ทำงาน แต่ไม่รวมsearch termอยู่ในผลลัพธ์

grep -i -E "search term" -ve "exclude term"

มีตัวเลือกอื่นสำหรับการยกเว้นหรือไม่เนื่องจากบางครั้งเราต้อง grep บรรทัดรอบคำและหากเราแยกในการดำเนินการครั้งต่อไปโดยใช้ '|' มันเพิ่งลบคำนั้น แต่ไม่ได้ลบบล็อกสำหรับคำนั้น
เรียน

คำตอบ:


40

ถึงและการแสดงออกด้วย grep คุณต้องมีการร้องขอสองรายการ:

grep -Ei "search term" | grep -Eiv "exclude term"

หากคำที่คุณค้นหาไม่ใช่นิพจน์ทั่วไปให้ใช้การจับคู่สตริงคงที่ ( -F) ซึ่งเร็วกว่า:

grep -F "search term" | grep -Fv "exclude term"

18

ขาดการเรียกใช้ grep สองครั้งมีเพียงวิธีเดียวที่ฉันคิดว่าจะทำสิ่งนี้ให้สำเร็จ มันเกี่ยวข้องกับPerl Compatible Regular Expressions (PCRE) และคำยืนยันบางอย่างที่ค่อนข้างยุ่งยาก

หากต้องการค้นหาfoo ที่ไม่รวมการแข่งขันที่มีแถบคุณสามารถใช้:

grep -P '(?=^((?!bar).)*$)foo'

นี่คือวิธีการทำงาน:

  • (?!bar)จับคู่สิ่งที่ไม่ใช่แถบโดยไม่ใช้อักขระจากสตริง จากนั้น.ใช้อักขระตัวเดียว

  • ^((?!bar).)*ทำซ้ำข้างต้นจากจุดเริ่มต้นของสตริง ( ^) ถึงจุดสิ้นสุดของมัน ( $) มันจะล้มเหลวหากbarพบ ณ จุดใด ๆ เนื่องจาก(?!bar)จะไม่ตรงกัน

  • (?=^((?!bar).)*$) ทำให้แน่ใจว่าสตริงตรงกับรูปแบบก่อนหน้าโดยไม่ต้องใช้อักขระจากสตริง

  • fooค้นหาfooตามปกติ

ฉันพบแฮ็คนี้ในนิพจน์ปกติเพื่อจับคู่สตริงที่ไม่มีคำหรือไม่ . ในคำตอบของ Bart Kiersคุณสามารถค้นหาคำอธิบายโดยละเอียดเพิ่มเติมเกี่ยวกับวิธีการมองโลกในแง่ลบ


แฮ็คที่ดี เคล็ดลับนี้ใช้ได้ใน Java ด้วยเช่นกัน
Raman

12

หากคุณต้องการทำสิ่งนี้ในการส่งครั้งเดียวคุณสามารถใช้ awk แทน grep

รูปแบบ:

echo "some text" | awk '/pattern to match/ && !/pattern to exclude/'

ตัวอย่าง:

  • echo "hello there" | awk '/hello/ && !/there/'

ไม่ส่งคืนอะไรเลย

  • echo "hello thre" | awk '/hello/ && !/there/'

คืนค่า: สวัสดี thre

  • echo "hllo there" | awk '/hello/ && !/there/'

ไม่ส่งคืนอะไรเลย

สำหรับหลายรูปแบบคุณสามารถใช้วงเล็บเพื่อจัดกลุ่มได้

ตัวอย่าง:

  • echo "hello thre" | awk '(/hello/ || /hi/) && !/there/'

คืนค่า: สวัสดี thre

  • echo "hi thre" | awk '(/hello/ || /hi/) && !/there/'

คืนค่า: สวัสดี

  • echo "hello there" | awk '(/hello/ || /hi/) && !/there/'

ไม่ส่งคืนอะไรเลย

  • echo "hi there" | awk '(/hello/ || /hi/) && !/there/'

ไม่ส่งคืนอะไรเลย


1
มันใช้งานได้สำหรับฉัน แต่ฉันทำสีหาย = P
Leopoldo Sanczyk

1
สีอะไรออกมา? หากคุณพยายามรักษาสีด้วย ls ให้ใช้อาร์กิวเมนต์ "--color = always" ทุกครั้งที่ทำการแยกวิเคราะห์ผลลัพธ์ (หรือโดยปกติคุณจะสูญเสียสีเมื่อทำการแยกวิเคราะห์ข้อความ) ตัวอย่าง: ls --color=always | awk '/hello/ && !/goodbye/'
Philip Reese

ขอบคุณสำหรับคำตอบ @Philip! ฉันเคยลองมาก่อน แต่ไม่ประสบความสำเร็จ ฉันเดาว่าเนื่องจากรูปแบบมีข้อความสีจึงไม่ตรงกันในภายหลังและฉันควรรวมรหัสสีบางประเภทไว้ในลวดลาย อย่างไรก็ตามคุณเป็นวิธีที่เร็วที่สุดที่ฉันพบgrep -Rในไฟล์โค้ดหลาย ๆ ไฟล์โดยใช้บรรทัดคำสั่งของ Ubuntu
Leopoldo Sanczyk

1

จากการทดลองของฉันมันไม่ได้มีรอยต่อที่จะสร้างความแตกต่างได้มากนักหากคุณใช้คำที่ไม่รวมของคุณผ่านgrepหรือsedหรือSed มีคุณสมบัติการแทนที่ข้อความที่มีประโยชน์อื่น ๆ ซึ่งฉันมักจะใช้เพื่อกรองเอาไฟล์บันทึก ดังนั้นฉันจะใช้ sed เมื่อรวมตัวกรองจำนวนมากเข้ากับ sed

wc /var/log/tomcat/tomcat.2013-01-14.log.1 
  1851725

 / usr / bin / time grep -i -E "(loginmanager)" /var/log/tomcat/tomcat.2013-01-14.log.1 | sed -e "/ login OK / d" -e "/ ล็อกอินหมดอายุ / d" | ห้องน้ำ
24.05 ผู้ใช้ 0.15 ระบบ 0: 25.27 ที่ผ่านมา 95% CPU (0avgtext + 0avgdata 3504 maxresident) k
0inputs + 0outputs (0major + 246minor) pagefaults 0swaps
   5614 91168 1186298

 / usr / bin / time grep -i -E "(loginmanager)" /var/log/tomcat/tomcat.2013-01-14.log.1 | sed -e "/ login OK / d" -e "/ ล็อกอินหมดอายุ / d" | ห้องน้ำ
23.50 ผู้ใช้ 0.16 ระบบ 0: 24.48 ผ่าน 96% CPU (0avgtext + 0avgdata 3504 maxresident) k
0inputs + 0outputs (0major + 246minor) pagefaults 0swaps
   5614 91168 1186298

 / usr / bin / time grep -i -E "(loginmanager)" /var/log/tomcat/tomcat.2013-01-14.log.1 | grep -v -e "เข้าสู่ระบบตกลง" -e "เข้าสู่ระบบหมดอายุ" | ห้องน้ำ
23.08 ผู้ใช้ 0.14 ระบบ 0: 23.55 ผ่านการประมวลผล 98% CPU (0avgtext + 0avgdata 3504 maxresident) k
0inputs + 0outputs (0major + 246minor) pagefaults 0swaps
   5614 91168 1186298

 / usr / bin / time grep -i -E "(loginmanager)" /var/log/tomcat/tomcat.2013-01-14.log.1 | grep -v -e "เข้าสู่ระบบตกลง" -e "เข้าสู่ระบบหมดอายุ" | ห้องน้ำ
23.50 ผู้ใช้ 0.15 ระบบ 0: 25.27 ที่ถูกปิดใช้งาน CPU 93% (0avgtext + 0avgdata 3488 maxresident) k
0inputs + 0outputs (0major + 245minor) pagefaults 0swaps
   5614 91168 1186298


3
ลองเปรียบเทียบรันไทม์grep -Fแทนgrep -Eและอย่าใช้-iถ้าคุณไม่ต้องการ
ธ อร์

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