ฉันจะ grep สำหรับสิ่งนี้หรือว่า (2 สิ่ง) ในไฟล์ได้อย่างไร


37

ฉันมีไฟล์ที่มี "แล้ว" และ "มี" ของ

ฉันสามารถ

$ grep "then " x.x
x and then some
x and then some
x and then some
x and then some

และฉันสามารถ

$ grep "there " x.x
If there is no blob none some will be created

ฉันจะค้นหาทั้งสองอย่างในการดำเนินการเดียวได้อย่างไร ฉันเหนื่อย

$ grep (then|there) x.x

-bash: ข้อผิดพลาดทางไวยากรณ์ใกล้โทเค็นที่ไม่คาดคิด `('

และ

grep "(then|there)" x.x
durrantm.../code
# (Nothing)

คำตอบ:


52

คุณต้องใส่นิพจน์ในเครื่องหมายคำพูด ข้อผิดพลาดที่คุณได้รับเป็นผลมาจากการทุบตีตีความ(ว่าเป็นตัวละครพิเศษ

นอกจากนี้คุณต้องบอก grep เพื่อใช้นิพจน์ปกติที่ขยายเพิ่ม

$ grep -E '(then|there)' x.x

โดยไม่ต้องแสดงออกปกติขยายคุณมีที่จะหลบหนี|, และ( )โปรดทราบว่าเราใช้เครื่องหมายคำพูดเดี่ยวที่นี่ Bash ถือว่าแบ็กสแลชภายในเครื่องหมายอัญประกาศคู่พิเศษ

$ grep '\(then\|there\)' x.x

การจัดกลุ่มไม่จำเป็นในกรณีนี้

$ grep 'then\|there' x.x

มันจำเป็นสำหรับบางสิ่งเช่นนี้:

$ grep 'the\(n\|re\)' x.x

3
ดูเพิ่มเติมและgrep $'then\nthere' grep -e then -e thereโปรดทราบว่า\|ไม่เป็นมาตรฐานใน BREs ที่เหลือก็คือ ทุบตี backslashes ถือว่าเป็นพิเศษภายในราคาคู่เท่านั้นก่อน", $, \ , `และขึ้นบรรทัดใหม่
Stéphane Chazelas

1
มีจุดประสงค์x.xอะไร?
alex

7

เพียงแค่ภาคผนวกอย่างรวดเร็วรสชาติส่วนใหญ่มีคำสั่งที่เรียกว่า egrep ซึ่งเป็นเพียง grep ด้วย -E โดยส่วนตัวผมชอบพิมพ์ที่ดีกว่ามาก

egrep "i(Pod|Pad|Phone)" access.log

กว่าจะใช้ grep -E


2

สิ่งที่บันทึกไว้ภายใต้การแสดงออกอย่างสม่ำเสมอในหน้า man (หรืออย่างน้อยของฉัน) เป็นจริงสำหรับregexps ขยาย ;

grep เข้าใจไวยากรณ์นิพจน์ทั่วไปสามเวอร์ชันที่แตกต่าง: "พื้นฐาน", "ขยาย" และ "perl" ใน GNU grep ไม่มีฟังก์ชั่นการใช้งานที่แตกต่างกันระหว่างไวยากรณ์พื้นฐานและขยาย ในการใช้งานอื่นนิพจน์ปกติพื้นฐานมีประสิทธิภาพน้อยกว่า คำอธิบายต่อไปนี้ใช้กับนิพจน์ทั่วไปที่ขยายเพิ่ม ความแตกต่างสำหรับการแสดงผลปกติพื้นฐานจะสรุปหลังจากนั้น

โดยปกติแล้ว grep จะไม่ใช้มัน - คุณต้องใช้-Eสวิตช์:

grep "(then|there)" x.x

เพราะ (จากหน้าคนอีกครั้ง):

นิพจน์พื้นฐานกับ Extended Regular Expression

ในการแสดงออกปกติพื้นฐานเมตาอักขระ,?, +, {, |, (และ) สูญเสียความหมายพิเศษของพวกเขา; ใช้แบ็กสแลชเวอร์ชัน \ ?, +, {, \ |, (และ) แทน

ดังนั้นคุณสามารถใช้:

grep "then\|there" x.x

เนื่องจากวงเล็บมีความฟุ่มเฟือยในกรณีนี้


0

ความเรียบง่ายสง่างามของ Bash ดูเหมือนว่าจะหลงทางในหน้าเพจขนาดใหญ่

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


หมายเหตุ: เชลล์สคริปต์ถูกใช้โดยตรง อินพุตบรรทัดที่พิมพ์เป็นส่วนขยายประวัติครั้งแรก

สายทุบตีแต่ละ tokenized แรกหรือในคำอื่น ๆ ที่สับเป็นสิ่งที่เรียกว่าราชสกุล (การโทเค็นเกิดขึ้นก่อนการขยายอื่น ๆ ทั้งหมดรวมถึงวงเล็บ, ตัวหนอน, พารามิเตอร์, คำสั่ง, เลขคณิต, กระบวนการ, การแยกคำ, และการขยายชื่อไฟล์)

โทเค็นที่นี่หมายถึงส่วนหนึ่งของบรรทัดอินพุตที่คั่น (คั่นด้วย) โดยหนึ่งในอักขระเมตาพิเศษเหล่านี้:

space,  - White space...
tab, 
newline,

‘<’,    - Redirection & piping...
‘|’, 
‘>’
‘&’,    - And/Both < | > | >>  .or.  &<file descriptor>

‘;’,    - Command termination

‘(’,    - Subshell, closed by -     ‘)’

Bash ใช้อักขระพิเศษอื่น ๆ อีกมากมาย แต่มีเพียง 10 ตัวเท่านั้นที่สร้างโทเค็นเริ่มต้น

อย่างไรก็ตามเนื่องจากบางครั้งต้องใช้เมตาอักขระเหล่านี้ในโทเค็นจึงจำเป็นต้องมีวิธีที่จะกำจัดความหมายพิเศษของพวกเขา สิ่งนี้เรียกว่าการหลบหนี การหลบหนีทำได้โดยการใส่สตริงของอักขระหนึ่งตัวหรือมากกว่านั้น (เช่น'xx..', "xx..") หรือโดยนำหน้าอักขระแต่ละตัวที่มีเครื่องหมายทับด้านหลัง (เช่น\x) (มันซับซ้อนกว่านี้เล็กน้อยเนื่องจากต้องใส่เครื่องหมายอัญประกาศด้วยเช่นกันและเนื่องจากเครื่องหมายคำพูดคู่ไม่ได้พูดทุกอย่าง แต่ตอนนี้การทำให้เรียบง่ายจะเกิดขึ้นในตอนนี้)

อย่าสับสนระหว่างการอ้างอิงข้อความโดยใช้ความคิดในการอ้างอิงข้อความเช่นในภาษาอื่น ๆ สิ่งที่อยู่ระหว่างเครื่องหมายอัญประกาศใน bash ไม่ใช่สตริง แต่เป็นส่วนของบรรทัดอินพุตที่มีเมตาอักขระที่หลบหนีดังนั้นจึงไม่คั่นโทเค็น

หมายเหตุมีความแตกต่างที่สำคัญระหว่าง'และ"แต่นั่นก็เป็นอีกวัน

เมตาอักขระที่ไม่ใช้ค่า Escape ที่เหลือจะกลายเป็นตัวคั่นโทเค็น

ตัวอย่างเช่น,

$ echo "x"'y'\g
xyg

$ echo "<"'|'\>
<|>

$ echo x\; echo y
x; echo y

ในตัวอย่างแรกมีสองราชสกุลผลิตโดยคั่นพื้นที่: และechoxyz

เช่นเดียวกันในตัวอย่างที่ 2

ในตัวอย่างที่สามอัฒภาครอดจึงมี 4 ราชสกุลผลิตโดยคั่นพื้นที่echo, x;, และecho yโทเค็นแรกจะถูกเรียกใช้เป็นคำสั่งและใช้โทเค็นสามตัวถัดไปเป็นอินพุต หมายเหตุที่ 2 echoจะไม่ถูกดำเนินการ


สิ่งสำคัญที่ต้องจำไว้คือลักษณะแรกทุบตีหนีตัวอักษร ( ', "และ\) แล้วมองหาที่ไม่ใช้ Escape คั่นเมตาตัวอักษรในลำดับที่

หากไม่ได้หลบหนีตัวละครพิเศษทั้ง 10 ตัวนี้จะทำหน้าที่เป็นtokenตัวคั่น บางคนมีความหมายเพิ่มเติม แต่ก่อนอื่นพวกเขาเป็นตัวคั่นโทเค็น


grep คาดหวังอะไร

ในตัวอย่างข้างต้น grep grepต้องการราชสกุลเหล่านี้string, filename,

คำถามแรกของคำถามคือ:

$ grep (จากนั้น | นั่น) xx

ในกรณีนี้(, )และ|ตัวละครที่ไม่ใช้ Escape เมตาและเพื่อทำหน้าที่ในการแยกการป้อนข้อมูลลงในราชสกุลเหล่านี้: grep, (, then, |, there, และ) x.xgrep ต้องการที่จะเห็นgrep, และthen|therex.x

คำถามที่สองคือ:

grep "(จากนั้น | ตรงนั้น)" xx

นี้ tokenizes เข้าgrep, ,(then|there) x.xคุณสามารถเห็นสิ่งนี้หากคุณสลับ grep สำหรับ echo:

echo "(จากนั้น | นั่น)" xx
(จากนั้น | นั่น) xx

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