2010-10-13 15 views
15

Tengo problemas para analizar el resultado del comando de tiempo en bash, e incluso para evitar que imprima su salida cuando lo llamo. Este es mi código de prueba:Comando de esfuerzo para analizar (bash)

#!/bin/bash 
TIME=`time ls -lh > /dev/null` 
echo "Testing..." 
echo $TIME 

este momento, imprime:

{blank-line} 
real 0m0.064s 
user 0m0.002s 
sys  0m0.005s 
Testing 
{blank-line} 

Por lo tanto, parece que el valor asignado a $TIME es la línea en blanco al comienzo del tiempo de impresión. Necesito obtener el valor de segundos de la línea sys, es decir, el "0.005". Tengo la garantía de que solo tendré segundos, así que no necesito nada antes de la "m"; sin embargo, la parte de segundos puede tener la forma de xx.xxx si va> = 10 segundos. Actualmente no tengo idea de cómo suprimir la salida de 'tiempo', capturarlo todo en lugar de la línea en blanco, ni analizarlo para obtener los valores que necesito.

Cualquier ayuda sería muy apreciada ...

Respuesta

16

Si se utiliza la orden interna Bash time, puede controlar su producción mediante la variable de TIMEFORMAT:

TIMEFORMAT=%R 

y usted no tendrá que hacer ningún análisis porque esto haría que time que sólo se emite el número de segundos.

y utilizar esto:

echo "Testing..." 
TIME=$({ time ls -lh > /dev/null; } 2>&1) 
echo $TIME 

o una de las otras técnicas de BashFAQ/032.

1

Las salidas de comando time la información de temporización a STDERR, que no está capturando o redireccionamiento. Entonces, en el momento de la asignación, esa información se imprime en su consola, mientras que la variable $TIME obtiene el STDOUT del comando, que se redirigió a /dev/null, por lo que está en blanco.

Quizás debería tratar de capturar el STDERR del comando?

+0

Ah, no me daba cuenta de que la producción tiempo para 'STDERR'. ¿Cómo puedo capturar eso en la variable '$ TIME' entonces? – Stephen

7

Lo primero y más importante es que los datos que intenta capturar se escriben en un error estándar. Pero capturar esa salida es bastante complicado en este caso.

time es tanto un ejecutable (en /usr/bin) como un comando de shell incorporado en bash y otras shells. Cuando ejecuta time sin especificar /usr/bin/time, está ejecutando un comando incorporado en bash. Esto hace que sea difícil hacer cosas con la salida, ya que bash no lo trata como un programa normal; es una función incorporada especial escrita por bash.

Sabiendo eso, y mirando la página de manual para time(1), puedo ver que los datos que está tratando de capturar desde time se envían a stderr. Así que mi solución para esto es para ejecutar directamente /usr/bin/time de la siguiente manera:

TIME=`/usr/bin/time ls -lh 2>&1 >/dev/null` 

Esto copia el flujo de error estándar a la salida estándar, y luego vuelve a dirigir lo que normalmente va a la salida estándar a /dev/null. El error estándar, sin embargo, seguirá siendo estándar ya que se duplicó antes de la redirección. Invertir el orden de estos no funcionará. (Sí, esto es confuso.)

Desafortunadamente, /usr/bin/time es un poco menos preciso en su salida:

0.00 real   0.00 user   0.00 sys 

Como alternativa, puede utilizar 2 sub-conchas, de la siguiente manera:

TIME=$((time ls -lh >/dev/null) 2>&1) 

Esto volvería a escribir lo que está escrito en el error estándar en la segunda subcadena dentro de la primera, lo que le permite capturar la salida. Consulte http://www.tldp.org/LDP/abs/html/subshells.html para obtener más información sobre subcapas.

+0

O use solo un sub-shell como 'TIME =" $ ({time ls -lh>/dev/null;} 2> & 1) ' –

0

Quería publicar esto como un comentario, pero sería demasiado largo. Quería presentar otra forma ligeramente diferente de obtener los datos.

Puede usar las dos subcadenas para obtener la salida del tiempo como una secuencia usando /bin/sh en lugar de /usr/bin/time para obtener el tiempo de ejecución. Me imagino que puedes sustituir time aquí con /usr/bin/time.

$ ((time ./print_test.sh > deleteme) 2>&1) > deletemetime 

$ cat deleteme 
test 

$ cat deletemetime 
./print_test.sh > deleteme 0.00s user 0.00s system 86% cpu 0.003 total 

$ ((time ./print_test.sh > deleteme) 2>&1) | sed 's/system/kernel/' 
./print_test.sh > deleteme 0.00s user 0.00s kernel 86% cpu 0.003 total 

Tenga en cuenta también que parece haber una diferencia en la forma en que producirá la salida. A veces es en ese formato y, a veces es en este formato:

real 0m0.420s 
user 0m0.385s 
sys  0m0.040s 

No es seguro en este momento lo que determina un modo u otro.

Por supuesto, puede usar p. Ej.

TIMEFORMAT='%3R' 

para corregir el formato.

2

Aunque las soluciones oscilan en torno a la misma lógica, pero todavía no pude encontrar lo siguiente en la lista, por lo que otra versión de la solución:

TIME=$(time (ls -lh >/dev/null) 2>&1) 
Cuestiones relacionadas