Piping output จากโปรแกรม segfaulting


13

ฉันมีสคริปต์ที่เรียกใช้โปรแกรม (โดยเฉพาะttf2afmส่วนหนึ่งของ tetex 3.0) ซึ่งบางครั้ง segfaults และบางครั้งก็ไม่มี ข้อมูลที่ฉันต้องการจะพิมพ์ออกมาเสมอก่อนที่จะแยก segfaults แต่ฉันประสบปัญหาในการหยุดการเปลี่ยนเส้นทางไปป์จากความล้มเหลวและไม่ส่งออกข้อมูลใด ๆ ไปยังไพพ์เมื่อโปรแกรมล้มเหลว

ฉันได้ลองเปลี่ยนเส้นทางผ่าน FIFO วงเล็บกระบวนการด้วยtrueตอนท้ายเรียกใช้จากฟังก์ชั่นเชลล์และการเข้ารหัสsh -cแต่ดูเหมือนว่าสคริปต์จะไม่ยอมให้กระบวนการส่งผลอะไรออกไป

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

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

ฉันใช้ BASH 4.1.10 (2) - ปล่อย

คำตอบ:


12

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

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

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

  • script เพิ่มบรรทัดส่วนหัวในไฟล์การถอดเสียงซึ่งคุณจะต้องลบภายหลัง
  • script ไม่ส่งคืนรหัสสถานะของคำสั่งดังนั้นคุณจะต้องบันทึกไว้ที่ใดที่หนึ่งหากคุณต้องการทราบเกี่ยวกับ segfault หรือข้อผิดพลาดอื่น ๆ
  • scriptจะทำให้เอาต์พุตปกติและข้อผิดพลาดหมดไป คุณควรบันทึกเอาต์พุตข้อผิดพลาดไปยังไฟล์แยกต่างหาก
export FONT="foo"
script -q -c '
    ttf2afm "$FONT.ttf" 2>"$FONT.ttf2afm-err";
    echo $? >"$FONT.ttf2afm-status"
' "$FONT.ttf2afm-typescript"
tail -n +2 <"$FONT.ttf2afm-typescript" >"foo.afm"
rm "$FONT.ttf2afm-typescript"
if [ "$(cat "$FONT.ttf2afm-status")" -ne 0 ]; then
  echo 1>&2 "Warning: ttf2afm failed"
  cat "$FONT.ttf2afm-err"
fi

ไม่มีวิธีที่สวยงามกว่านี้เช่นการตั้งค่าเชลล์บางอย่างที่จะตั้งค่าบัฟเฟอร์เอาต์พุตเป็น 0 หรือบางอย่าง?
แอมเฟตามาจิน

4

ในที่สุดฉันก็ค้นพบมันผ่านกระบวนการทดลองและข้อผิดพลาด วิธีการแก้ปัญหานั้นซับซ้อน:

(trap 'true' ERR; exec ttf2afm "$FONT") |
grep ...

เห็นได้ชัดว่าexecสาเหตุที่ttf2afmจะเข้าสู่กระบวนการ subshell กับข้อผิดพลาดที่ติดอยู่ทำให้เกิดการทำงานในสภาพแวดล้อมที่มันไม่สำคัญว่ามัน segfaults

การดักERRสัญญาณรวมทุกอย่างจะหยุดการ subshell จากการตายและการส่งสัญญาณไปยังสคริปต์หลัก - ซึ่งจะยุติทันทีหากมัน - เมื่อโปรแกรมล้มเหลว

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


3
ฉันดีใจที่มันใช้งานได้สำหรับคุณ แต่ฉันมั่นใจได้ว่าเหตุผลที่ใช้งานไม่ใช่เพราะ bash กำลังตั้งค่าขนาดบัฟเฟอร์เอาต์พุตเป็น 0 Bash ไม่สามารถมีอิทธิพลต่อการบัฟเฟอร์ที่ใช้ttf2afmโดยตรง ฉันสงสัยว่า(trap true ERR; exec ttf2afm "$FONT")| …จะทำตัวแตกต่างจากttf2afm "$FONT" | …อย่างไร
Gilles 'SO- หยุดความชั่วร้าย'
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.