ค้นหาสตริงที่แน่นอนด้วย grep


9

โดยวิธีการเช่นฉันเป็นไฟล์ข้อความขนาดใหญ่ที่มีที่อยู่อีเมลจำนวนมากโดยใช้ทุบตีฉันต้องการค้นหา / ตรวจสอบว่ามีอีเมลอยู่ (หรือไม่) ควรจะใช้ "เบรก" เท่านั้นหรือไม่

grep '^user1@example.com' text_file

หรือว่ามีวิธีที่ดีกว่า ฉันต้องการสร้างสคริปต์ทุบตีและฉันต้องการความปลอดภัย


1
อีเมลเป็นคำเดียวในบรรทัดหรือไม่
เกล็นแจ็คแมน

จริง: ไฟล์มีรูปแบบนี้: user1@example.com example.com/user1
Pol Hallen

1
ในกรณีนี้ฉันจะใช้grep -q '^user1@example\.com\>'- โดยมีตัวยึดเส้นตรงในตอนเริ่มต้นและจุดยึดท้ายคำท้ายคำ
glenn jackman

คำตอบ:


24

ดูตัวเลือก-F(สตริงคงที่ซึ่งตรงข้ามกับนิพจน์ทั่วไป) และ-x(แน่นอน: จับคู่ทั้งบรรทัด)

grep -Fx user1@example.com text_file

จะเท่ากับ:

grep '^user1@example\.com$' text_file

(จำไว้ว่า.เป็นตัวดำเนินการนิพจน์ทั่วไปที่ตรงกับอักขระใด ๆ )

ใช้-qตัวเลือกหากคุณต้องการตรวจสอบว่ามีบรรทัดดังกล่าวหรือไม่:

grep -Fxq user1@example.com text_file &&
  echo yes, that address is in that file.

หากบรรทัดที่ต้องการค้นหาและชื่อไฟล์เป็นตัวแปร:

grep -Fxqe "$email" < "$file"

หรือ

grep -Fxq -- "$email" < "$file"

คุณไม่ต้องการ:

grep -Fxq "$email" "$file"

เป็นที่จะทำให้เกิดปัญหาหาก$emailหรือเริ่มต้นด้วย$file-

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

printf '%s\n' user1@example.com | comm -12 - text_file

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

comm -12 text_file emails_to_check

จะเร็วกว่า:

grep -Fxf emails_to_check text_file

AFAIK grep -Fxq -- "$email" "$file"ยังใช้งานได้
vinc17

stephane ทำไมคุณเปลี่ยนจากอินพุตไฟล์ (จัดการโดย grep) เป็น stdin โดยใช้<redirector? มีข้อดีอะไรบ้าง?
umläute

@ umläuteและ vinc17 -ที่ผมกล่าวก็เพื่อให้ครอบคลุมสำหรับชื่อไฟล์ที่เริ่มต้นด้วย แม้grep -- "$email" "$file"จะเป็นปัญหาสำหรับไฟล์ที่เรียกว่า-(ซึ่งgrepถือว่าเป็นพิเศษตามความหมายstdin )
Stéphane Chazelas

6

เพื่อให้มีประสิทธิภาพมากที่สุดคุณต้องหยุดหลังจากพบคู่แรก หากคุณมี GNU grepคุณสามารถทำได้:

grep -m 1 '^user1@example\.com$' your_file

ถ้าคุณทำไม่ได้คุณสามารถใช้ Perl:

perl -nlE 'say and last if $_ eq q{user1@example.com}' your_file

4
-mเฉพาะ GNU ใช้ POSIX -qหากคุณต้องการตรวจสอบอย่างมีประสิทธิภาพว่ามีบรรทัดดังกล่าว
Stéphane Chazelas

3

มีการตรวจสอบอีเมลจำนวนมากที่นั่น หนึ่งในนั้นคือ:

grep -E -o "\b[a-zA-Z0-9.-]+@[a-zA-Z0-9.-]+\.[a-zA-Z0-9.-]+\b" text_file

เพื่ออธิบายคำตอบของฉันอย่างละเอียด

คุณใช้^จุดยึดซึ่งระบุจุดเริ่มต้นของสตริง สิ่งนี้จะไม่ตรงกันหากที่อยู่อีเมลอยู่ระหว่างสตริงที่มีความยาว


2
ขอบคุณ นั่นคือตัวเลือก grep ทั่วไปในการ "แยก" ที่อยู่อีเมลทั้งหมดในไฟล์ ฉันต้องการค้นหาที่อยู่อีเมลทีละหนึ่งโดยใช้อ่าน EMAIL จากนั้นใช้ grep เพื่อตรวจสอบ
Pol Hallen

2

grepคำสั่งของคุณจะจับคู่ทุกอย่างที่ขึ้นต้นด้วย^user1@example.comรวมถึงที่อยู่อีเมลด้วยเช่นuser1@example.com.spammer.comกัน เนื่องจาก.เป็นอักขระพิเศษในนิพจน์ทั่วไปที่ตรงกับคีย์ใด ๆ คุณจึงควรหลีกเลี่ยงเป็น\.

สมมติว่าไฟล์ข้อความของคุณมีหนึ่งที่อยู่ต่อบรรทัดให้ใช้:

EMAIL=user1@example\\.com
egrep "^${EMAIL}$" text_file

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


1
user1@example-comที่ยังไม้ขีดไฟ
Stéphane Chazelas

@ StéphaneChazelasแน่นอน อัปเดตคำตอบ
umläute

@ umläuteคุณต้องเพิ่มแบ็กสแลชเป็นสองเท่า -Fxแต่มันเป็นเรื่องที่ดีที่จะใช้
vinc17

@ vinc17, doh; ทุบตีหนี; อย่างไรก็ตามฉันยอมรับว่ามันเป็นการดีกว่าที่จะใช้-Fxแต่นั่นคือคำตอบของ stephane :-)
umläute

0

พิจารณาการจับคู่ตัวอักษร / สตริงที่ตรงกันทั่วไป:

grep -w "search_word" <file>  >  output.txt

#\b shows boundaries over here.

หรือ,

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