2012-10-05 2 views
7

He estado siguiendo algunas de las preguntas similares (como How to set a variable to the output from a command in Bash?), sin embargo, las respuestas aceptadas parecen no funcionar para mí. No estaba seguro de si debería descarrilar la pregunta de otra persona o publicar mi propio duplicado, así que me disculpo si escogí mal aquí.Cómo obtener salida de un comando bash en una variable

Deseo obtener el estado de salida y salida de una serie de comandos en un script que estoy reuniendo. Aquí está un ejemplo de lo que he estado usando:

cmd_output=$(rm $file) 
exit_status=$? 
if [ "${exit_status}" -eq 0 ] 
then 
log "Successfully removed the original" ${TAB_LEVEL} 
else 
fail "Failed to remove the original, the output was: \n ${cmd_output}" 
fi 

El registro y rechazo funciones son:

# Usage: fail "Failure message" 
function fail { 
echo "FATAL ERROR: $1" >> "${LOG_DIR}/${LOG_FILE}" 
exit 1 
} 

# Usage: log "Log message" 3 Where the tab-level is 3. 
function log { 
if (("${2}" > 0)) 
then 
eval "printf ' %.0s' {1..$2}" >> "${LOG_DIR}/${LOG_FILE}" 
fi 
echo "$1" >> "${LOG_DIR}/${LOG_FILE}" 
return 0 
} 

En el ejemplo anterior utilizo el formato $ (cmd), pero también he intentado usando apoyos.

En mi archivo de registro, todo lo que veo cuando hay un fallo es:

FATAL ERROR: Failed to remove the original, the output was: \n

Además, la salida de los comandos fallidos termina en la pantalla como de costumbre. ¿Hay alguna razón común por la que mis variables cmd_output permanezcan vacías?

Respuesta

22

Usted tiene que incluir la salida de la corriente de salida de error estándar especial:

cmd_output=$(rm "$file" 2>&1) 

Hay tres corrientes de defecto en todos los programas (que se numeran los descriptores de fichero):

0. Standard input (where the program normally reads from) 
1. Standard output (where the program normally writes to) 
2. Standard error (where the program normally writes error messages) 

Así que para capturar los mensajes de error, debemos redirigir la salida de error estándar (stderr) a la salida estándar normal (stdout) que luego será capturada por la expresión $(...).

La sintaxis para la redirección es a través del > "operador". Inmediatamente antes, diga qué descriptor de archivo redirigir (el valor predeterminado es 1, que es stdout). Y puede especificarlo para redirigir a un archivo. Si escribe un ampersand (&) después de él, lo fuerza a redirigir a otro descriptor de archivo. Por lo tanto, en este ejemplo, redirigiremos el descriptor de archivo 2 (stderr) al descriptor de archivo 1 (stdout).

Además, también puede redirigir la entrada con < "operador", pero en este caso el descriptor de archivo predeterminado es 0 (stdin).

Otra observación es que probablemente sea una buena práctica colocar su variable $file entre comillas dobles, en caso de que tenga caracteres de espacio en blanco.

Espero que esto ayude un poco =)

+1

Me alegro de empujarte por encima de la marca 1000, sigue publicando! – shellter

+0

Hola Janito, muchas gracias por tu respuesta! Soy consciente de los tres flujos estándar y operadores de redirección, pero la única razón por la que los he utilizado hasta ahora es para enviar todo desde un comando a/dev/null o a un archivo de registro. Ni siquiera consideré las diferentes corrientes aquí. La variable $ file en realidad estaba originalmente entre comillas, lo saqué de comillas cuando estaba probando las funciones de captura de errores de mi script, para forzar un error. Nuevamente, ¡muchas gracias! –

5

* comando nix generalmente tienen dos formas de salida: salida estándar (stdout) y el error estándar (stderr).

FOO=$(...) solo captura stdout, y deja stderr sin obstáculos.

Si desea que los contenidos de stderr con esta sintaxis, es necesario a Postfix su comando con el fin de que 2>&1stderr se combina en stdout. (p.ej.de este modo: rm $file 2>&1)

+0

Hola antak, solo quería decir muchas gracias por tu respuesta. Como Janito's es un poco más detallado, lo dejo como la respuesta aceptada, pero agradezco mucho su ayuda :). –

0

Debido a que su función fail se acaba saliendo, sería mucho más fácil simplemente hacer:

set -e # Abort on failure 
exec 2>> "${LOG_DIR}/${LOG_FILE}" # Append all errors to LOG_FILE 
if cmd_output=$(rm $file) 
    log "Successfully removed the original" ${TAB_LEVEL} 
fi 

La única diferencia entre este y el código original es que no lo hace de impresión el texto FATAL ERROR:. Como la brevedad es una virtud, probablemente sería mejor omitir la función log por completo. Informe los errores en voz alta; tener éxito en silencio.

+0

Gracias William. En este caso, no quiero tener éxito de forma silenciosa, aunque si estuviera escribiendo un paquete para distribución u otros fines, estaría de acuerdo. Sin embargo, este es un software interno, y tan importante como mover los archivos es que mantiene detalles muy claros sobre lo que se ha tocado (gran parte de lo que se está moviendo son datos confidenciales o críticos). También necesito el prefijo FATAL ERROR - el archivo de registro es procesado por la máquina, los datos se copian para buscar ese o algunos otros prefijos de línea. ¡Gracias de nuevo! –

Cuestiones relacionadas