grep สามารถส่งคืนจริง / เท็จหรือมีวิธีการอื่น


130

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

grep ^$1 schemas.txt

ฉันรู้สึกว่ามันน่าจะง่ายกว่าที่ฉันทำ

ฉันได้รับข้อผิดพลาด "มีการโต้แย้งมากเกินไป" ในifคำสั่ง ฉันกำจัดช่องว่างระหว่างgrep -qแล้วก็เกิดข้อผิดพลาดของผู้ให้บริการไบนารี่

if [ grep -q ^$1 schemas.txt ]
then
        echo "Schema already exists. Please try again"
        exit 1
else
        echo "$@" >> schemas.txt
fi

1
เสีย[... ]และมันจะได้ผล แม้ว่าคุณอาจต้องการที่จะพูดรูปแบบของคุณ:if grep -q "^$1" schemas.txt; then …
derobert

โซลูชันบรรทัดเดียวที่ใช้คุณสมบัติ "คำสั่งกลุ่ม" ของ Bash: stackoverflow.com/questions/6550484/…
เทรเวอร์บอยด์สมิ ธ

คำตอบ:


186

grepส่งคืนรหัสการออกที่แตกต่างกันหากพบบางสิ่ง (เป็นศูนย์) และหากไม่พบสิ่งใด (ไม่ใช่ศูนย์) ในifคำสั่งรหัสการออกเป็นศูนย์จะถูกแมปกับ "จริง" และรหัสการออกที่ไม่เป็นศูนย์จะถูกแมปเป็นเท็จ นอกจากนี้ grep ยังมี-qอาร์กิวเมนต์ที่จะไม่ส่งออกข้อความที่ตรงกัน (แต่จะส่งคืนรหัสสถานะการออกเท่านั้น)

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

if grep -q PATTERN file.txt; then
    echo found
else
    echo not found
fi

ในฐานะที่เป็นโน้ตย่อเมื่อคุณทำอะไรบางอย่างif [ -z "$var" ]…มันจะกลาย[เป็นว่าคำสั่งที่คุณใช้อยู่นั้นเหมือนกับ grep /usr/bin/[ในระบบของฉันมันเป็น (ในทางเทคนิคแล้วเชลล์ของคุณอาจมีอยู่แล้วภายใน แต่ก็เป็นการปรับให้เหมาะสมมันทำงานเสมือนว่าเป็นคำสั่ง) มันทำงานในลักษณะเดียวกัน[ส่งคืนรหัสทางออกที่เป็นศูนย์สำหรับจริงรหัสทางออกที่ไม่เป็นศูนย์สำหรับเท็จ ( testเป็นสิ่งเดียวกับ[ยกเว้นการปิด])


ทำไมคำสั่ง if ถึงไม่ต้องการวงเล็บ? ฉันทำงานไม่ได้ แต่ไม่เข้าใจว่าทำไม ฉันยังคงทำรังโดยไม่ใส่วงเล็บได้ไหม?
ลอเรน

@ Lauren คุณพลาดบันทึกย่อหรือไม่ [ไม่ได้เป็นส่วนหนึ่งของไวยากรณ์ถ้ามัน (แนวคิด) คำสั่งคุณกำลังใช้งานเช่นเดียวกับ grep
derobert

2
@ Lauren คุณไม่ได้ใช้ grep ภายในของ [คุณใช้อย่างใดอย่างหนึ่งขึ้นอยู่กับเงื่อนไขที่คุณต้องการตรวจสอบ (คุณสามารถใช้คำสั่งใดก็ได้ภายใน if, btw, ถ้าเพียงตรวจสอบรหัสทางออก) ... ดีฉันคิดว่าคุณน่าจะมีเหตุผลที่จะใช้ grep ภายใน [แต่นั่นก็เป็นสคริปต์ที่ค่อนข้างซับซ้อนและ ไม่ใช่เรื่องปกติที่ต้องทำ
Derobert

3
FYI เรียกใช้ls -l /usr/bin/\[และman [เพื่อดูว่า[เป็นโปรแกรมเหมือน ๆ กันมันแค่ดูเหมือนองค์ประกอบวากยสัมพันธ์ - สิ่งนี้ควรทำให้ชัดเจนและเข้าใจง่ายขึ้น (เพื่อความสะดวก[ยังเป็น bash, dash และอื่น ๆ ในตัว - แต่มันยังคงเป็นคำสั่ง) ลองtype -all [ทุบตี
cas

1
@AlexanderCska หากคุณต้องการให้ grep พิมพ์บรรทัดที่ตรงกัน (เช่นไปที่แป๊ปเดียว) จากนั้นข้าม-qตัวเลือกนั้นจะบอก grep ให้เงียบ (ไม่พิมพ์บรรทัดที่ตรงกัน)
Derobert

47

grep -cอีกวิธีที่ง่ายคือการใช้

เอาต์พุตนั้น (ไม่ส่งคืนเป็นรหัสออก) จำนวนบรรทัดที่ตรงกับรูปแบบดังนั้น 0 หากไม่มีการจับคู่หรือ 1 หรือมากกว่าหากมีการจับคู่

ดังนั้นหากคุณต้องการตรวจสอบว่ารูปแบบตรงกัน 3 ครั้งขึ้นไปคุณจะทำ:

if [ "$(grep -c "^$1" schemas.txt)" -ge 3 ]; then
  ...

17
แม่นยำยิ่งขึ้นมันจะออก 1 หากพบเพียงครั้งเดียว เพื่อส่งออก 1 โดยไม่คำนึงถึงจำนวนเงินของการแข่งขันพบว่าใช้grep -cim1แทน
จัดการ

วิธีนี้ยังสามารถใช้เพื่อแยกความแตกต่างระหว่างข้อผิดพลาด grep และ grep 'รูปแบบพบ 0 ครั้ง' (ถึงแม้จะไม่ได้อยู่กับที่แน่นอนถ้ามีคำสั่งที่ใช้ผมคิดว่าตัวแปรที่จำเป็น)
อีวานเบนน์

3

ฉันรู้ว่าฉันมาสายสำหรับเรื่องนี้ แต่ฉันชอบรุ่นสั้น ๆ นี้:

grep -q ^$1 schemas.txt && echo "Schema already exists. Please try again" || echo "$@" >> schemas.txt

0

ถ้าเราต้องการที่จะจับคำแรกของไฟล์ที่เราต้องการจะเพิ่ม-zwใน grep

if grep -qzw "^$1" file
then 
   ... 
else 
   ... 
fi

หากปราศจาก-zเราจะได้คำแรกของบรรทัด โดยที่-wเราไม่ได้รับคำบางส่วน


-2

หากคุณต้องการใช้กับวงเล็บเหลี่ยมคุณสามารถดำเนินการด้านล่าง

if [ `grep -q PATTERN file.txt` ]; then
    echo found
else
    echo not found

ลอจิกนี้ใช้ได้กับทุกคำสั่งเพียงแค่วางคำสั่งของคุณไว้ใน backtick (ปุ่มด้านบนแท็บหรือไปที่ปุ่มลงของ Esc หรือทางซ้ายของปุ่ม 1)


1
คุณต้องใส่เครื่องหมายอัญประกาศ`grep -q PATTERN file.txt`มิฉะนั้นจะใช้ตัวดำเนินการแบ่ง + glob และนั่นจะทำให้เกิดปัญหาสำหรับผลลัพธ์ที่มีอักขระ$IFSหรืออักขระตัวแทน โดยทั่วไปแล้ว[ "`cmd`" ]จะส่งคืนค่าจริงหากcmdเอาต์พุตอย่างน้อยหนึ่งบรรทัดที่ไม่ว่างบน stdout (มีปัญหาที่อาจเกิดขึ้นหากเอาต์พุตเป็น NUL ไบต์) นั่นหมายความว่าเชลล์จะต้องเก็บเอาท์พุททั้งหมดในหน่วยความจำและรอให้มันเสร็จสิ้น การใช้งานif cmd | grep -q .แทนอาจจะดีกว่าในเรื่องนั้น
Stéphane Chazelas

คำสั่งนี้จะไม่สมเหตุสมผลเลย วัตถุประสงค์ของ-qสวิตช์คือเพื่อหยุด grepเอาต์พุตของ คุณกำลังพูดว่า: ตรวจสอบ PATTERN ใน file.txt ระงับเอาต์พุตใด ๆ จากนั้นตั้งค่าสถานะการส่งคืนตามว่าพบ PATTERN จากนั้นให้เพิกเฉยสถานะการคืนสินค้าออกคำสั่ง (ซึ่งเราบังคับให้ว่าง) ใช้การแยกคำและการขยายไฟล์ glob (ส่งผลให้ไม่มีข้อโต้แย้งเลย) จากนั้นเรียกใช้คำสั่ง[(aka test) ด้วยอาร์กิวเมนต์หนึ่งตัว - , ]--and แล้วตั้งแต่ที่จะมีผลในข้อผิดพลาด echo "ไม่พบ" @ StéphaneChazelasฉันพลาดอะไรไปรึเปล่า?
Wildcard

1
@Wildcard -qคุณขวาฉันเห็นได้ชัดมองข้าม ความคิดเห็นนั้นจะสมเหตุสมผล[ `grep PATTERN file.txt ` ]แต่ตามคำแนะนำในความคิดเห็น[ "`grep -n PATTERN file.txt`" ]จะดีกว่าถ้ารูปแบบอาจตรงกับบรรทัดว่างเท่านั้น แม้ว่าที่นี่แน่นอนif grep -q PATTERN file.txtคุณต้องการ
Stéphane Chazelas
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.