ป้องกัน grep ไม่ให้ออกในกรณีที่มีการระบุชื่อ


29

สคริปต์นี้ไม่ได้สะท้อน "หลัง":

#!/bin/bash -e

echo "before"

echo "anything" | grep e # it would if I searched for 'y' instead

echo "after"
exit

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


นี่คือการสังเกตหมายถึงการพิจารณาเท่านั้น บางทีตรรกะของสคริปต์นี้ควรได้รับการพิจารณาอีกครั้ง หากไม่มีความสำคัญในการค้นหาสตริงทำไมค้นหามัน? คำจำกัดความของ grep เป็นสิ่งที่ทำให้การตัดสินใจขึ้นอยู่กับการมีอยู่ของสตริง หากคุณไม่สนใจวิธีใดก็ไม่สำคัญ นอกจากนี้ยังดูเหมือน-eว่าคุณจะใส่ใจ: มากเพื่อให้ปัญหาใด ๆ ที่เป็นความหายนะ
Andrew Falanga

2
@AndrewFalanga ฉันสนใจอย่างใดอย่างหนึ่งตั้งแต่ฉันวิเคราะห์เนื้อหาvar=$(complex command | grep complex_pattern)ที่อาจเป็นโมฆะ (ในกรณีที่โปรแกรมของฉันไม่ควรยุติ) นี่เป็นสคริปต์ที่ทำให้คุณเกิดปัญหา ไม่มีช่องโหว่อภิปรัชญาในตรรกะที่นี่ใช่ไหม ;)
iago-lito

ตอนนี้รู้ว่าคุณตั้งใจจะจับเอาท์พุทจะชี้แจงบางสิ่งบางอย่าง ตามที่ปรากฏมันทำให้ฉันสับสน
Andrew Falanga

คำตอบ:


33
echo "anything" | grep e || true

คำอธิบาย:

$ echo "anything" | grep e
### error
$ echo $?
1
$ echo "anything" | grep e || true
### no error
$ echo $?
0
### DopeGhoti's "no-op" version
### (Potentially avoids spawning a process, if `true` is not a builtin):
$ echo "anything" | grep e || :
### no error
$ echo $?
0

"| |" หมายถึง "หรือ" หากส่วนแรกของคำสั่ง "ล้มเหลว" (หมายถึง "grep e" จะส่งคืนโค้ดออกที่ไม่เป็นศูนย์) จากนั้นส่วนหลัง "||" จะถูกดำเนินการประสบความสำเร็จและกลับเป็นศูนย์ในขณะที่รหัสทางออก ( trueกลับเป็นศูนย์เสมอ)


3
รุ่นที่สั้นกว่าเล็กน้อยที่ไม่หมุน/bin/trueคือ: command || :(ในกรณีของคุณ, set -e; grep 'needle' haystack || :)
DopeGhoti

1
@DopeGhoti trueเป็นกระสุนในตัว (อย่างน้อยก็bash 4.3ใน RHEL)
iruvar

3
ไม่ถูกต้องเพราะหากคำสั่งแรกล้มเหลวมันจะซ่อนข้อผิดพลาด ทางออกที่ถูกต้องควรกลับไม่ใช่ศูนย์ถ้าคำสั่งแรกในไปป์ล้มเหลว
โซริน

11

วิธีที่แข็งแกร่งในการส่งข้อความอย่างปลอดภัยและเป็นทางเลือก grep :

echo something | grep e || [[ $? == 1 ]] ## print 'something', $? is 0
echo something | grep x || [[ $? == 1 ]] ## no output, $? is 0
echo something | grep --wrong-arg e || [[ $? == 1 ]] ## stderr output, $? is 1

ตามคู่มือ posixรหัสทางออก 1 หมายถึงไม่มีการเลือกบรรทัดและ> 1 หมายถึงข้อผิดพลาด


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

7

ตัวเลือกอื่นคือการเพิ่มคำสั่งอื่นไปป์ไลน์ - สิ่งที่ไม่ล้มเหลว:

echo "anything" | grep e | cat

เพราะcatตอนนี้เป็นคำสั่งสุดท้ายในไปป์ไลน์มันเป็นสถานะทางออกของcatไม่ใช่ของgrepที่จะถูกใช้เพื่อตรวจสอบว่าไปป์ไลน์ล้มเหลวหรือไม่



3

วิธีการแก้

#!/bin/bash -e

echo "before"

echo "anything" | grep e || : # it would if I searched for 'y' instead

echo "after"
exit

คำอธิบาย

set -e หรือ set -o errexit

ออกทันทีหากไปป์ไลน์ (ซึ่งอาจประกอบด้วยคำสั่งง่าย ๆเดียว) รายการหรือคำสั่งผสม (ดูSHELL GRAMMARด้านบน) ออกด้วยสถานะที่ไม่เป็นศูนย์ เชลล์ไม่ออกหากคำสั่งที่ล้มเหลวเป็นส่วนหนึ่งของรายการคำสั่งที่ตามหลังwhileหรือuntilคำหลักส่วนหนึ่งของการทดสอบทำตามคำifหรือelifคำสงวนส่วนหนึ่งของคำสั่งใด ๆ ที่ดำเนินการใน&&หรือ||รายชื่อยกเว้นคำสั่งที่ตามหลังสุดท้าย &&หรือ||ใด ๆ คำสั่งในไปป์ไลน์ แต่สุดท้ายหรือถ้าค่าส่งคืนของคำสั่งจะถูกคว่ำด้วย!. หากคำสั่งผสมอื่นที่ไม่ใช่-eเชลล์ย่อยส่งคืนสถานะที่ไม่เป็นศูนย์เนื่องจากคำสั่งล้มเหลวขณะที่ถูกละเว้นเชลล์จะไม่ออก กับดักERRถ้าตั้งค่าจะถูกดำเนินการก่อนที่จะออกจากเปลือก ตัวเลือกนี้ใช้กับสภาพแวดล้อมของเชลล์และแต่ละสภาพแวดล้อมของเชลล์ย่อยแยกต่างหาก (ดูCOMMAND EXECUTION ENVIRONMENTด้านบน) และอาจทำให้ subshells ออกก่อนที่จะดำเนินการคำสั่งทั้งหมดใน subshell

นอกจาก:นี้ยังเป็นคำสั่งไม่มีผลใน Bash

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