พฤติกรรมของ "eval" ภายใต้ "set -e" ในการแสดงออกตามเงื่อนไข


10

พิจารณาคำสั่ง

eval false || echo ok
echo also ok

ปกติเราจะคาดหวังนี้จะดำเนินการfalseสาธารณูปโภคและเนื่องจากสถานะออกเป็นที่ไม่ใช่ศูนย์ไปแล้วดำเนินการและecho okecho also ok

ในทุก POSIX เหมือนเปลือกหอยที่ผมใช้ ( ksh93, zsh, bash, dash, OpenBSD kshและyash) นี้เป็นสิ่งที่เกิดขึ้น set -eแต่สิ่งที่ได้รับที่น่าสนใจถ้าเราเปิดใช้งาน

หากset -eมีผล OpenBSD ของshและkshเปลือกหอย (มาทั้งจากpdksh) evalจะยุติสคริปต์เมื่อการดำเนินการ ไม่มีเปลือกอื่นทำ

POSIX บอกว่าข้อผิดพลาดในยูทิลิตี้บิวด์อินพิเศษ (เช่นeval) ควรทำให้เชลล์ที่ไม่มีการโต้ตอบหยุดทำงาน ฉันไม่แน่ใจทั้งหมดว่าการดำเนินการfalseถือเป็น "ข้อผิดพลาด" (ถ้าเป็นเช่นนั้นจะเป็นอิสระจากset -eการใช้งาน)

วิธีแก้ปัญหานี้ดูเหมือนว่าจะใส่ไว้evalในเปลือกย่อย

( eval false ) || echo ok
echo also ok

คำถามคือว่าฉันคาดว่าจะต้องทำอย่างนั้นในสคริปต์เชลล์ที่ถูกต้อง POSIX หรือไม่หรือว่าเป็นข้อบกพร่องในเชลล์ของ OpenBSD หรือไม่ นอกจากนี้ "ความผิดพลาด" ในข้อความ POSIX ที่เชื่อมโยงกับด้านบนมีความหมายอย่างไร


ข้อมูลบิตพิเศษ: เชลล์ OpenBSD จะดำเนินการecho okทั้งที่มีและไม่มีset -e ในคำสั่ง

eval ! true || echo ok

รหัสเดิมของฉันดูเหมือน

set -e
if eval "$string"; then
    echo ok
else
    echo not ok
fi

ซึ่งจะไม่ส่งออกnot okด้วยการstring=falseใช้เปลือกหอย OpenBSD (มันจะยุติ) และฉันไม่แน่ใจว่ามันเป็นโดยการออกแบบโดยไม่ได้ตั้งใจหรือโดยความเข้าใจผิดหรืออย่างอื่น


eval falseสร้างสถานะที่ไม่ใช่ศูนย์ดังนั้นฉันคาดว่าset -eจะยุติสคริปต์ในตอนนั้น ในกรณีที่! set -eไม่ได้ใช้เป็น!คำสั่งตรวจสอบสถานะการออกอย่างชัดเจน
fcbsd

@fcbsd คุณคาดว่าeval falseจะยุติสคริปต์แม้ว่าจะเป็นส่วนหนึ่งของรายการ AND-OR หรือคำสั่งแบบมีเงื่อนไข? ฉันจะไม่
Kusalananda

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

ต้องเล่นกันมากขึ้นโดยใช้ sh บน CentOS 7 - ฉันจะบอกว่านั่นเป็นพฤติกรรมที่ตั้งใจไว้สำหรับ ksh / sh ของ OpenBSD เมื่อใช้set -eดังนั้น `() คือคำตอบ
fcbsd

คำตอบ:


4

ที่ไม่มีเชลล์อื่นที่ต้องการการแก้ไขปัญหาดังกล่าวเป็นข้อบ่งชี้ที่แข็งแกร่งว่าเป็นข้อบกพร่องใน OpenBSD ksh ในความเป็นจริง ksh93 ไม่แสดงปัญหาดังกล่าว

ว่ามีอยู่||ในบรรทัดคำสั่งจะต้องหลีกเลี่ยงการออกจากเปลือกที่เกิดจากการส่งกลับรหัส 1 ที่ด้านซ้ายของมัน

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

continue 3

builtin ที่ปล่อยข้อผิดพลาดที่ชัดเจน แต่ไม่ออก

ดังนั้นการออกบนfalseจะถูกสร้างขึ้นโดยset -eเงื่อนไขไม่ใช่โดยคุณสมบัติ builtin ของคำสั่ง ( evalในกรณีนี้)

เงื่อนไขที่แน่นอนที่set -eจะออกจะค่อนข้างเลือนลางใน POSIX


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

4

[ขออภัยถ้านี่ไม่ใช่คำตอบที่แท้จริงฉันจะอัปเดตเมื่อฉันได้รับมัน]

ฉันได้ดูซอร์สโค้ดและข้อสรุปของฉันคือ:

1) มันเป็นข้อผิดพลาด / ข้อ จำกัด ไม่มีอะไรอยู่เบื้องหลังปรัชญา

2) "แก้ไข" สำหรับมันจากส้อมแบบพกพาของ OpenBSD's ksh ( mksh) แย่มากเพียง แต่ทำสิ่งที่แย่กว่านั้นโดยไม่ต้องแก้ไข:

ใหม่บั๊กแตกต่างจากหอยอื่น ๆ ทั้งหมด:

mksh -ec 'eval "false; echo yup"'
yup

bash -ec 'eval "false; echo yup"'
(nothing)

ยังไม่ได้รับการแก้ไขจริงๆ:

mksh -ec 'eval "set -e; false" || echo yup'
(nothing)

bash -ec 'eval "set -e; false" || echo yup'
yup

คุณสามารถเปลี่ยนbashข้างต้นด้วยdash, zsh, yash, ksh93ฯลฯ

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