Трубопровід виводиться з програми segfaulting


13

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

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

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

Моє запитання: чи є в скрипті спосіб ігнорувати той факт, що програма segfault і все одно давати мені вихід?

Я запускаю BASH 4.1.10 (2) -випуск.

Відповіді:


12

Програми, як правило, захищають свої результати для ефективності. Тобто вони накопичують вихід в області пам'яті (називається буфером), і вони фактично отримують вихід лише тоді, коли буфер заповнений або в певні ключові моменти програми. Коли програма закінчується нормально, вона промиває вихідний буфер (тобто виводить будь-які дані, що залишилися в ньому). Коли вона переходить у параметр segfault, вміст буфера втрачається.

Ви не спостерігаєте цього ефекту під час запуску програми безпосередньо в терміналі, оскільки поведінка відрізняється, коли вихід програми підключений до терміналу (на відміну від звичайного файлу або труби). У терміналі типовою поведінкою є промивання буфера в кінці кожного рядка. Таким чином, ви побачите кожен повний рядок, який виробляється до моменту, коли програма починає здійснюватись.

Ви можете змусити програму запускатися в терміналі і збирати її вихід. Найпростіший спосіб - бігти 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взяти на себе процес підзагортання із захопленою помилкою, змушуючи його працювати в середовищі, де не має значення, чи є це segfaults.

Уловлювання ERRсигналу " все включено" призведе до того, що підрозділ не вмирає та надсилатиме сигнал до основного сценарію - який припиняється негайно, якщо це відбувається - коли програма не працює.

Єдина проблема полягає в тому, що саме ядро видасть цілу купу сміття слідів стека безпосередньо на консольний пристрій після того, як процес буде виконаний, і тому немає можливості запобігти його виведенню [про що я знаю], але це не має значення оскільки це не впливає на stdout або stderr.


3
Я радий, якщо це працює для вас, але можу впевнено стверджувати, що причина цього не полягає в тому, що bash встановлює розмір вихідного буфера на 0. Баш не може впливати на буферизацію, яку використовує ttf2afmбезпосередньо. Цікаво, як (trap true ERR; exec ttf2afm "$FONT")| …вдається вести себе інакше ttf2afm "$FONT" | ….
Жил "ТАК - перестань бути злим"
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.