2010-03-09 13 views
35

Para redirigir (y anexar) stdout y stderr a un archivo, mientras que también se presentan en el terminal, hago esto:bash: redirigir (y anexar) stdout y stderr al archivo y el terminal y obtener el código de salida adecuada

command 2>&1 | tee -a file.txt 

Sin embargo, ¿hay otra manera de hacer esto para que obtenga un valor preciso para el estado de salida?

Es decir, si pruebo $?, quiero ver el estado de salida de command, no el estado de salida de tee.

Sé que puedo usar ${PIPESTATUS[0]} aquí en lugar de $?, pero estoy buscando otra solución que no implique tener que comprobar PIPESTATUS.

+2

¿Por qué no quieres usar 'PIPESTATUS'? –

+0

Duplicados: http://stackoverflow.com/questions/985876/tee-and-exit-status, http: // stackoverflow.com/questions/1221833/bash-tee-output-and-capture-exit-status – jpalecek

Respuesta

30

Tal vez usted podría poner el valor de salida de PIPESTATUS en $?

command 2>&1 | tee -a file.txt ; (exit ${PIPESTATUS}) 
6

Otra posibilidad, con algunos bash sabores, es activar la opción pipefail:

pipefail

Si establecer, el valor de retorno de una tubería es el valor de la última (más a la derecha) comm y para salir con un estado distinto de cero , o cero si todos los comandos en la tubería salen exitosamente. Esta opción está deshabilitada de forma predeterminada.

set -o pipefail 
... 
command 2>&1 | tee -a file.txt || echo "Command (or tee?) failed with status $?" 

Dicho esto, la única manera de lograr la funcionalidad PIPESTATUS forma portátil (por ejemplo, por lo que también trabajaría con POSIX sh) es un poco complicado, es decir, se requiere un archivo temporal para propagar una estado de salida del tubo de nuevo al proceso shell padre:

{ command 2>&1 ; echo $? >"/tmp/~pipestatus.$$" ; } | tee -a file.txt 
if [ "`cat \"/tmp/~pipestatus.$$\"`" -ne 0 ] ; then 
    ... 
fi 

o, encapsulado para su reutilización:

log2file() { 
    LOGFILE="$1" ; shift 
    { "[email protected]" 2>&1 ; echo $? >"/tmp/~pipestatus.$$" ; } | tee -a "$LOGFILE" 
    MYPIPESTATUS="`cat \"/tmp/~pipestatus.$$\"`" 
    rm -f "/tmp/~pipestatus.$$" 
    return $MYPIPESTATUS 
} 

log2file file.txt command param1 "param 2" || echo "Command failed with status $?" 

o, más genéricamente quizá:

save_pipe_status() { 
    STATUS_ID="$1" ; shift 
    "[email protected]" 
    echo $? >"/tmp/~pipestatus.$$.$STATUS_ID" 
} 

get_pipe_status() { 
    STATUS_ID="$1" ; shift 
    return `cat "/tmp/~pipestatus.$$.$STATUS_ID"` 
} 

save_pipe_status my_command_id ./command param1 "param 2" | tee -a file.txt 
get_pipe_status my_command_id || echo "Command failed with status $?" 

... 

rm -f "/tmp/~pipestatus.$$."* # do this in a trap handler, too, to be really clean 
3

Hay una forma POSIX arcano de hacer esto:

exec 4>&1; R=$({ { command1; echo $? >&3 ; } | { command2 >&4; } } 3>&1); exec 4>&- 

esta forma se establece la variable R que el valor de retorno de command1, y el tubo de salida de command1 a command2, cuya salida se redirige a la salida del shell primario.

4

Uso proceso de sustitución:

command > >(tee -a "$logfile") 2>&1 

camiseta se ejecuta en un subnivel de manera $? mantiene el estado de salida del comando .

Cuestiones relacionadas