2015-07-24 13 views
5

Sto cercando di aggiungere alcune informazioni di fronte ad ogni uscita di linea da un file, da:Proxy ordine tenuta output/error in bash

  • cattura sia stdout e stderr
  • anteponendo le informazioni
  • output al manico originale

Ecco il mio script di test:

#!/bin/bash 
# 
# Test proxying stdout and stderr 
# 

function proxy-stdouterr() { 
    local name="$1" 
    local handle=$2 
    while IFS='' read -r line 
    do 
     echo -e "[ ${name}: ${line} ]" >&${handle} 
    done 
} 

# Output some messages and attempt to parse them 
(
    echo "1: Normal message" 
    echo "2: Error" >&2 
    echo "3: Normal message" 
    echo "4: Error" >&2 
) 2> >(proxy-stdouterr "stderr" 2) > >(proxy-stdouterr "stdout" 1) 

Questo funziona abbastanza bene, ma non conserva l'ordine nel terminale (Ubuntu 12.04).

uscite Quando non proxy:

1: Normal message 
2: Error 
3: Normal message 
4: Error 

Tuttavia quando proxy l'ordine non viene mantenuta. Peggio ancora questo non è deterministica, la maggior parte del tempo è:

[ stderr: 2: Error ] 
[ stderr: 4: Error ] 
[ stdout: 1: Normal message ] 
[ stdout: 3: Normal message ] 

Ma di tanto in tanto:

[ stderr: 2: Error ] 
[ stdout: 1: Normal message ] 
[ stderr: 4: Error ] 
[ stdout: 3: Normal message ] 

Come posso risolvere questo problema?

Grazie

+0

Penso che questo sia un problema di sincronizzazione di base: quando i produttori scrivono a una risorsa condivisa in parallelo, non è possibile garantire l'ordine in cui tali scritture avvengono senza una qualche forma di coordinamento. – larsks

+2

Inoltre, +1 per fornire un esempio che mostri chiaramente la domanda! – larsks

+0

larsk è corretto. L'output viene suddiviso in due flussi di I/O separati: STDOUT e STDERR (i "produttori"), che vengono quindi "proxy", prefissati e quindi richiamati alla console. Il tempo per elaborare ogni flusso può variare, specialmente con una funzione bash come parte dello stream, quindi non c'è modo di sincronizzare il loro output (senza usare alcun tipo di segnale). – aks

risposta

1

Come altri hanno notato, questo è un problema di sincronizzazione con nessuna evidente risposta senza sapere di più su quali parti di controllare specificamente e desideri modificare.

ci sono secondo me due superfici principali di attacco:

  • flusso di buffering. La maggior parte dei programmi derivati ​​da C non buffer stderr, buffer stdin e stdout per riga se sono un terminale e buffer completamente altrimenti. Questo spiega perché lo stderr tende sempre a essere all'inizio nell'esempio. Un cop-out economico è quello di utilizzare /usr/bin/echo invece che incorporato nello echo, in modo da ottenere un flusso scaricato alla fine di ogni riga (e un sacco di ritardo per la generazione del processo). Risolve il tuo esempio 100% per quello che ho provato, quindi potrebbe essere abbastanza per te anche . Se hai il controllo sul comando che genera le linee, assicurati che sia stdout sia stderr siano bufferizzati dalla linea.

  • pianificazione del processo. Hai due processi in competizione per leggere da entrambi i flussi. Se ci sono dati che fluiscono su entrambi al momento, sono in una gara uno contro l'altro. È possibile mitigare tale da avere un unico processo di farlo, ma non sono sicuro che sia possibile mantenerlo efficiente nel nativo bash (senza POSIX programmabile select a disposizione dell'utente finale)

In In ogni caso, se c'è una coda ovunque nell'immagine, sei avvitato per quanto riguarda il mantenimento dell'ordine.