Emissione di piping da un programma di segfaulting


13

Ho uno script che chiama un programma (in particolare ttf2afm, parte di tetex 3.0) che a volte segfault e a volte no. Le informazioni di cui ho bisogno vengono sempre stampate prima che si interrompano, ma faccio fatica a fermare il reindirizzamento della pipe dal fallimento e non emettere nulla alla pipe quando il programma fallisce.

Ho provato a reindirizzare tramite un FIFO, tra parentesi il processo con truea alla fine, eseguendolo da una funzione shell e racchiudendolo sh -c, ma lo script non sembra mai consentire al processo di produrre nulla , reindirizzato o meno, nemmeno a stderr.

So che è in grado di produrre, essendo perfettamente in grado di darlo dalla riga di comando, ma non da uno script per qualche motivo.

La mia domanda è: c'è un modo per lo script di ignorare il fatto che il programma segfault e mi dà comunque l'output?

Sto eseguendo BASH 4.1.10 (2)-release.

Risposte:


12

I programmi in genere bufferizzano il loro output per efficienza. Cioè, accumulano l'output in un'area di memoria (chiamata buffer) e in realtà ottengono l'output solo quando il buffer è pieno o in determinati punti chiave del programma. Quando il programma termina normalmente, svuota il buffer di output (ovvero stampa tutti i dati che sono rimasti in esso). Quando segfault, il contenuto del buffer viene perso.

Non si osserva questo effetto quando si esegue il programma direttamente in un terminale perché il comportamento è diverso quando l'output del programma è collegato a un terminale (al contrario di un file normale o di una pipe). In un terminale, il comportamento predefinito è svuotare il buffer alla fine di ogni riga. Quindi vedrai ogni riga completa prodotta fino al punto in cui il programma segfault.

È possibile forzare l'esecuzione del programma in un terminale e raccoglierne l'output. Il modo più semplice è correre script. Ci sono una serie di fastidi che dovrai risolvere:

  • script aggiunge una riga di intestazione al file di trascrizione, che dovrai rimuovere in seguito.
  • script non restituisce il codice di stato del comando, quindi è necessario salvarlo da qualche parte se si desidera conoscere il segfault o qualsiasi altro errore.
  • scriptcauserà l'uscita normale e l'errore; faresti meglio a salvare l'output dell'errore in un file separato.
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

Non esiste una soluzione più elegante, come un'impostazione della shell che imposta il buffer di output su 0 o qualcosa del genere?
anfetamachina,

4

Alla fine l'ho capito attraverso un processo di tentativi ed errori. La soluzione è in qualche modo contorta:

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

Apparentemente le execcause ttf2afmsubentrano al processo della subshell con l'errore intercettato, facendolo funzionare in un ambiente in cui non ha importanza se segfault.

L'intrappolamento del ERRsegnale all-inclusive impedirà alla subshell di morire e di inviare un segnale allo script principale, che terminerà immediatamente in caso contrario, quando il programma fallisce.

L'unico problema è che il kernel stesso genererà un sacco di spazzatura di stack stack direttamente sul dispositivo console una volta che il processo segfault, quindi non c'è modo di impedirne l'output [che io conosco], ma non importa poiché non influisce su stdout o stderr.


3
Sono contento se questo funziona per voi, ma posso tranquillamente sostengono che il motivo per cui funziona è non perché bash sta impostando la dimensione del buffer di uscita a 0. Bash non può influenzare il buffer usato da ttf2afmdirettamente. Mi chiedo come (trap true ERR; exec ttf2afm "$FONT")| …riesca a comportarsi diversamente da ttf2afm "$FONT" | ….
Gilles 'SO- smetti di essere malvagio' il
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.