[t] นิพจน์วงเล็บปีกกานี้ใน grep ทำงานอย่างไร


38

ฉันเห็นหนึ่งซับนี้เมื่อเร็ว ๆ นี้:

$ ps -ef | grep [f]irefox 

thorsen   16730     1  1 Jun19 ?        00:27:27 /usr/lib/firefox/firefox ...

ดังนั้นดูเหมือนว่าจะส่งคืนรายการกระบวนการด้วย "firefox" ในข้อมูล แต่ไม่รวมกระบวนการ grep เองและดังนั้นจึงดูเหมือนว่าจะเทียบเท่ากับ:

ps -ef |grep -v grep| grep firefox

ฉันไม่เข้าใจว่ามันทำงานอย่างไร ฉันดูหน้า man บน grep และที่อื่น ๆ แล้ว แต่ไม่พบคำอธิบาย

และเพิ่มความลึกลับถ้าฉันวิ่ง:

$ ps -ef | grep firefox  > data
$ grep [f]irefox data

thorsen   15820 28618  0 07:28 pts/1    00:00:00 grep --color=auto firefox
thorsen   16730     1  1 Jun19 ?        00:27:45 /usr/lib/firefox/firefox ....

rick [t] ดูเหมือนว่าจะหยุดทำงาน!

ใครบางคนที่นี่จะรู้ว่าเกิดอะไรขึ้นฉันแน่ใจ

ขอบคุณ


อืมคุณแน่ใจหรือว่าถูกต้อง? ps -eaf | grep [fF] irefox น่าจะสมเหตุสมผลมากกว่า ดูเหมือนว่าจะเป็นนิพจน์ทั่วไปและหมายถึงจับคู่หนึ่งในอักขระที่ล้อมรอบ สามารถทำได้เช่นเดียวกันกับช่วงเช่น [0-9]
mbs

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

คำตอบ:


57

นิพจน์วงเล็บเหลี่ยมเป็นส่วนหนึ่งของเชลล์ bash (และเชลล์อื่น ๆ เช่นกัน)การจับคู่รูปแบบคลาสอักขระของ grep

grepโปรแกรมโดยค่าเริ่มต้นเข้าใจนิพจน์ปกติ POSIX พื้นฐาน โดยที่คุณสามารถกำหนดคลาสตัวละคร ตัวอย่างเช่นps -ef | grep [ab9]irefoxจะหา " a irefox", " b irefox", " 9 irefox" หากมีอยู่ แต่ไม่ใช่ " ab irefox"

คำสั่งgrep [a-zA-Z0-9]irefoxจะค้นหากระบวนการทั้งหมดที่เริ่มต้นด้วยตัวอักษรหรือตัวเลขหนึ่งตัวและลงท้ายด้วย "irefox"

ดังนั้นps -ef | grep firefoxการค้นหาบรรทัดด้วยfirefoxในนั้น เนื่องจากกระบวนการ grep เองนั้นมี "firefox" อยู่ในนั้น grep จึงพบเช่นกัน ด้วยการเพิ่ม a []เราจะค้นหาเฉพาะคลาสอักขระ "[f]" (ซึ่งประกอบด้วยเฉพาะตัวอักษร "f" เท่านั้นและเทียบเท่ากับเพียงแค่ "f" โดยไม่มีเครื่องหมายวงเล็บ) ข้อดีของวงเล็บตอนนี้คือสตริง "firefox" จะไม่ปรากฏในคำสั่ง grep อีกต่อไป ดังนั้น grep ตัวเองจะไม่ปรากฏในผลลัพธ์ grep

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

หากคุณต้องการแก้ไขผลลัพธ์ที่สองคุณสามารถใช้วิธีนี้:

ps -ef | grep [f]irefox  > data
grep firefox data

(อ้างอิง)


1
อืมมม มันไม่ได้เกิดขึ้นกับฉันว่า [] เป็นสิ่งที่ตีความโดยเชลล์ก่อนที่ grep grep จะได้รับโอกาสแม้แต่ ขอบคุณสำหรับคำอธิบาย แก้ไข [m] ทั้งหมดแล้ว
Thorsen

ยินดีที่ได้ช่วย. ขอให้มีความสุขในวันนี้ :)
jokerdino

1
ใน bash วงเล็บเหลี่ยมจะถูกส่งผ่านไปยัง grep หากไม่มีการจับคู่คำที่อยู่ (เช่นไม่มีไฟล์ชื่อ "firefox" ในไดเรกทอรีปัจจุบัน) อย่างไรก็ตาม grep ยังมีคลาสของตัวอักษรและ [f] ใน grep ก็เหมือนกับ f
Daniel Hershcovich

6
ที่จริงแล้วในกรณีนี้ฉันไม่คิดว่ามันจะถูกตีความโดยเชลล์ก่อน grep ฉันคิดว่า[f]เป็นวงเล็บเหลี่ยมจับคู่รูปแบบนิพจน์ทั่วไปสำหรับคลาสอักขระ เช่นเดียวกับใน "[a-z0-9] grep irefox" จะตรงกับ "airefox" และ "0irefox" เช่นกัน คุณสามารถเห็นว่าไม่ใช่ bash ในตัวตั้งแต่echo $([f])ส่งคืนข้อผิดพลาด
con-f-use

4
เหตุผลเฉพาะที่[f]irefoxใช้ได้กับวัตถุประสงค์นี้คือมันไม่ได้ถูกขยายโดยเชลล์ เมื่อเชลล์ขยาย[f]irefoxไปถึงfirefoxสิ่งนั้นgrepจะทำให้มองเห็นfirefoxและจากนั้นfirefoxเป็นส่วนหนึ่งของgrepสตริงคำสั่งของเหมือนกับว่าgrep firefoxถูกเรียกใช้ แต่มันเป็นเรื่องดีที่จะทำให้การจับคู่แบบเปลือกในใจโดยเฉพาะอย่างยิ่งเมื่อมีการเขียนสคริปต์เพราะถ้ามีไฟล์ที่เรียกว่าfirefoxในไดเรกทอรีปัจจุบัน , แล้วเปลือกไม่ขยาย[f]irefoxไปfirefoxและวิธีการนี้ล้มเหลวกล่าวคือgrepเส้นpsจะแสดง
Eliah Kagan

10

เหตุผลก็คือสตริง

grep firefox

ตรงกับรูปแบบfirefoxแต่สตริง

grep [f]irefox

ไม่ตรงกับรูปแบบ[f]irefox(ซึ่งเทียบเท่ากับรูปแบบfirefox)

นั่นเป็นเหตุผลที่ grep แรกตรงกับบรรทัดคำสั่งของกระบวนการขณะที่ตัวที่สองไม่


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