Saída de piping de um programa de segfaulting

12

Eu tenho um script que chama um programa (especificamente, ttf2afm , parte do tetex 3.0) que às vezes é segmentado e às vezes não. A informação que eu preciso é sempre impressa antes dos segfaults, mas estou tendo dificuldades em parar o redirecionamento do pipe de falhar e não produzir nada para o pipe quando o programa falha.

Eu tentei redirecionar por meio de um FIFO, colocando o parêntese no processo com true no final, executando a partir de uma função de shell e encapsulando em sh -c , mas o script nunca parece deixar o processo nada , redirecionado ou não - nem mesmo para stderr.

Eu sei que é capaz de produzir, sendo que é perfeitamente capaz de dar a partir da linha de comando, mas não de um script por algum motivo.

A minha pergunta é, existe alguma maneira para o script ignorar o fato de que o programa segfaults e me dar a saída de qualquer maneira?

Estou executando o BASH 4.1.10 (2) -release.

    
por amphetamachine 24.07.2011 / 23:05

2 respostas

4

Eu finalmente descobri através de um processo de tentativa e erro. A solução é meio confusa:

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

Aparentemente, o exec faz com que ttf2afm assuma o processo de subshell com o erro trapped, fazendo com que ele opere em um ambiente onde não importa se ele gera segfaults.

Trapping o sinal ERR do all-inclusive irá parar a sub-camada de morrer e enviar um sinal para o script principal - que terminará imediatamente se isso acontecer - quando o programa falhar.

O único problema é que o próprio kernel produzirá um monte de lixo de rastreio de pilha diretamente para o dispositivo de console uma vez os segfaults do processo, então não há como evitar de ser saída [que eu sei de], mas isso não importa, pois não afeta stdout ou stderr.

    
por 25.07.2011 / 04:23
8

Os programas normalmente armazenam em buffer sua saída para eficiência. Ou seja, eles acumulam saída em uma área de memória (chamada de buffer) e, na verdade, obtêm a saída somente quando o buffer está cheio ou em determinados pontos-chave do programa. Quando o programa termina normalmente, ele libera o buffer de saída (isto é, imprime todos os dados que restam nele). Quando ocorre o segfault, o conteúdo do buffer é perdido.

Você não observa este efeito ao executar o programa diretamente em um terminal porque o comportamento é diferente quando a saída do programa é conectada a um terminal (em oposição a um arquivo regular ou a um pipe). Em um terminal, o comportamento padrão é liberar o buffer no final de cada linha. Portanto, você verá todas as linhas completas produzidas até o ponto em que os segfaults do programa.

Você pode forçar o programa a ser executado em um terminal e coletar sua saída. A maneira mais simples é executar script . Há vários inconvenientes que você precisa resolver:

  • script adiciona uma linha de cabeçalho ao arquivo de transcrição, que você precisará remover depois.
  • script não retorna o código de status do comando, então você precisa salvá-lo em algum lugar se quiser saber sobre o segfault ou qualquer outro erro.
  • script causará saída normal e erro; é melhor salvar a saída do erro em um arquivo separado.
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
    
por 25.07.2011 / 02:29