Đầu ra đường ống từ một chương trình segfaulting


13

Tôi có một đoạn script gọi một chương trình (cụ thể ttf2afmlà một phần của tetex 3.0) đôi khi tách biệt và đôi khi không. Thông tin tôi cần luôn được in ra trước khi phân tách , nhưng tôi gặp khó khăn trong việc ngăn chuyển hướng đường ống không thành công và không xuất bất cứ thứ gì vào đường ống khi chương trình bị lỗi.

Tôi đã thử chuyển hướng thông qua một FIFO, truecuối cùng là ngoặc đơn cho quá trình , thực thi từ hàm shell và mã hóa sh -c, nhưng tập lệnh dường như không bao giờ để quá trình xuất ra bất cứ thứ gì , chuyển hướng hay nói cách khác là thậm chí không để stderr.

Tôi biết nó có khả năng xuất ra, vì nó hoàn toàn có khả năng đưa nó từ dòng lệnh, nhưng không phải từ một kịch bản vì một số lý do.

Câu hỏi của tôi là, có cách nào để script bỏ qua thực tế là chương trình segfaults và cung cấp cho tôi đầu ra không?

Tôi đang chạy BASH 4.1.10 (2).

Câu trả lời:


12

Các chương trình thường đệm đầu ra của chúng cho hiệu quả. Nghĩa là, họ tích lũy đầu ra trong một vùng nhớ (được gọi là bộ đệm) và họ thực sự chỉ nhận được đầu ra khi bộ đệm đầy hoặc tại một số điểm chính trong chương trình. Khi chương trình kết thúc bình thường, nó sẽ xóa bộ đệm đầu ra (nghĩa là in ra bất kỳ dữ liệu nào còn lại trong đó). Khi nó segfaults, nội dung của bộ đệm bị mất.

Bạn không quan sát hiệu ứng này khi chạy chương trình trực tiếp trong thiết bị đầu cuối vì hành vi sẽ khác khi đầu ra của chương trình được kết nối với thiết bị đầu cuối (trái ngược với tệp thông thường hoặc đường ống). Trong một thiết bị đầu cuối, hành vi mặc định là để xóa bộ đệm ở cuối mỗi dòng. Do đó, bạn sẽ thấy mọi dòng hoàn chỉnh được tạo ra cho đến khi chương trình tách biệt.

Bạn có thể buộc chương trình chạy trong một thiết bị đầu cuối và thu thập đầu ra của nó. Cách đơn giản nhất là chạy script. Có một số phiền toái mà bạn sẽ cần phải giải quyết:

  • script thêm một dòng tiêu đề vào tệp bản ghi mà bạn sẽ cần phải xóa sau đó.
  • script không trả về mã trạng thái của lệnh, vì vậy bạn sẽ cần lưu nó ở đâu đó nếu bạn muốn biết về segfault hoặc bất kỳ lỗi nào khác.
  • scriptsẽ gây ra đầu ra bình thường và lỗi ra; bạn nên lưu đầu ra lỗi vào một tệp riêng biệt.
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

Không có một giải pháp nào thanh lịch hơn, như một số cài đặt shell sẽ đặt bộ đệm đầu ra thành 0 hoặc một cái gì đó?
amphetamachine

4

Cuối cùng tôi đã tìm ra nó thông qua một quá trình thử và sai. Các giải pháp là loại phức tạp:

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

Rõ ràng các execnguyên nhân ttf2afmđể tiếp nhận quá trình subshell với lỗi bị mắc kẹt, khiến nó hoạt động trong một môi trường không có vấn đề gì nếu nó tách biệt.

Bẫy ERRtín hiệu bao gồm tất cả sẽ ngăn không cho mạng con chết và gửi tín hiệu đến tập lệnh chính, điều này sẽ chấm dứt ngay lập tức nếu nó bị lỗi khi chương trình bị lỗi.

Vấn đề duy nhất là bản thân hạt nhân sẽ tạo ra cả đống rác theo dõi ngăn xếp trực tiếp đến thiết bị console sau khi phân tách quá trình, vì vậy không có cách nào để ngăn chặn nó xuất ra [mà tôi biết], nhưng điều đó không thành vấn đề vì nó không ảnh hưởng đến thiết bị xuất chuẩn hoặc thiết bị xuất chuẩn.


3
Tôi rất vui nếu điều này hiệu quả với bạn, nhưng tôi có thể tự tin khẳng định rằng lý do nó hoạt động không phải vì bash đang đặt kích thước bộ đệm đầu ra thành 0. Bash không thể ảnh hưởng ttf2afmtrực tiếp đến bộ đệm được sử dụng . Tôi tự hỏi làm thế nào (trap true ERR; exec ttf2afm "$FONT")| …quản lý để cư xử khác nhau từ ttf2afm "$FONT" | ….
Gilles 'SO- ngừng trở nên xấu xa'
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.