Вывод данных из программы segfaulting

13

У меня есть скрипт, который вызывает программу (в частности, ttf2afmчасть tetex 3.0), которая иногда вызывает ошибки, а иногда нет. Информация, которая мне нужна, всегда выводится на печать до того , как она выйдет из строя , но мне трудно остановить сбой перенаправления канала и не выводить что-либо в канал при сбое программы.

Я попытался перенаправить через FIFO, заключив в скобки процесс с trueконечным символом, выполнив из функции оболочки и заключив в него sh -c, но, похоже, что скрипт никогда не позволяет процессу выводить что-либо , перенаправленное или иным образом - даже в stderr.

Я знаю, что он способен выводить данные, поскольку он вполне способен выдавать его из командной строки, но не по какой-либо причине из сценария.

У меня вопрос, есть ли способ для сценария игнорировать тот факт, что программа segfaults и дать мне результат в любом случае?

Я использую BASH 4.1.10 (2) -релиз.

amphetamachine
источник

Ответы:

12

Программы обычно буферизуют свой вывод для эффективности. То есть они накапливают выходные данные в области памяти (называемой буфером) и фактически выводят выходные данные только тогда, когда буфер заполнен или в определенных ключевых точках программы. Когда программа завершается нормально, она очищает выходной буфер (то есть выводит все данные, которые в ней есть). Когда происходит сбой, содержимое буфера теряется.

Вы не наблюдаете этот эффект при запуске программы непосредственно в терминале, потому что поведение отличается, когда вывод программы подключен к терминалу (в отличие от обычного файла или канала). В терминале по умолчанию используется очистка буфера в конце каждой строки. Поэтому вы увидите каждую полную строку, созданную до того момента, когда программа выйдет из строя.

Вы можете заставить программу работать в терминале и собирать ее вывод. Самый простой способ - бежать 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 с перехваченной ошибкой заставляют его работать в среде, где не имеет значения, происходит ли сбой.

Перехват ERRсигнала «все включено» предотвратит гибель подоболочки и передачу сигнала основному сценарию, который немедленно прекратит работу, если произойдет сбой программы.

Единственная проблема состоит в том, что само ядро будет выводить целую кучу мусора трассировки стека непосредственно на консольное устройство после того, как процесс завершит работу с ошибками, поэтому нет способа предотвратить его вывод [это я знаю], но это не имеет значения поскольку это не влияет на стандартный вывод или стандартный вывод.

amphetamachine
источник
3
Я рад, что это работает для вас, но я могу с уверенностью утверждать, что причина этого не в том, что bash устанавливает размер выходного буфера в 0. Bash не может влиять на буферизацию, используемую ttf2afmнапрямую. Интересно, как (trap true ERR; exec ttf2afm "$FONT")| …удается вести себя иначе, чем ttf2afm "$FONT" | ….
Жиль "ТАК - перестань быть злым"