Me gustaría mostrar el tiempo de finalización de un script.
Lo que hago actualmente es –
#!/bin/bash date ## echo the date at start # the script contents date ## echo the date at end
Esto solo muestra la hora de inicio y finalización del script. ¿Sería ¿Es posible mostrar una salida detallada como tiempo de procesador / tiempo de io, etc.?
Comentarios
- stackoverflow.com/questions/385408/ …
- Creo que la respuesta aceptada actual no es suficiente debido a las fluctuaciones temporales.
- @CiroSantilli 烏坎 事件 2016 六四 事件 法轮功 Creo que el hilo propuesto aún no es suficiente para eliminar el efecto de los eventos temporales.
- También relacionado: stackoverflow.com/questions/5152858/… o algo unix.stackexchange.com/questions/334145 / …
- Hay un comando que puede ejecutar y luego cronometra todos los comandos de Unix automáticamente, ¿olvidó cómo habilitarlo?
Responder
Jus t use time
cuando llame al script:
time yourscript.sh
Comentarios
- Esto genera tres veces:
real
,user
ysys
. Para conocer el significado de estos, consulte aquí . - y » real » es probablemente lo que la gente quiere saber – » Real es la hora del reloj de pared – tiempo desde el inicio hasta el final de la llamada »
- ¿Hay alguna forma de capturar la salida estándar en un archivo? Por ejemplo, algo como
time $( ... ) >> out.txt
- También puede hacer esto con secuencias de comandos en la línea de comandos, por ejemplo:
time (command1 && command2)
- O podría, en su script, simplemente hacer: echo $ SECONDS asumiendo que es bash ….
Responder
Si time
no es «una opción,
start=`date +%s` stuff end=`date +%s` runtime=$((end-start))
Comentarios
- Tenga en cuenta que esto solo funciona si no ‘ t necesita precisión inferior a un segundo. Para algunos usos, esto podría ser aceptable , para otros no. Para una precisión ligeramente mejor (usted ‘ todavía está invocando
date
dos veces, por ejemplo, por lo que podría en mejor obtenga una precisión de milisegundos en la práctica, y probablemente menos), intente usardate +%s.%N
. (%N
son nanosegundos ya que el segundo .) - @ChrisH Oh. Es bueno señalarlo; la expansión aritmética de bash es solo de enteros. Veo dos obvi nuestras opciones; O deshaga el período en la cadena de formato de fecha (y trate el valor resultante como nanosegundos desde época), así que use
date +%s%N
, o use algo más capaz comobc
para calcular el tiempo de ejecución real a partir de los dos valores, como sugiere jwchew. Aún así, creo que este enfoque es una forma subóptima de hacerlo;time
es considerablemente mejor si está disponible, por las razones descritas anteriormente. - Simplemente instale
bc
y luego haga esto:runtime=$( echo "$end - $start" | bc -l )
- Si su secuencia de comandos tarda varios minutos, utilice:
echo "Duration: $((($(date +%s)-$start)/60)) minutes
- Además de @ rubo77 comenta, si tu secuencia de comandos tarda varias horas, utiliza
hours=$((runtime / 3600)); minutes=$(( (runtime % 3600) / 60 )); seconds=$(( (runtime % 3600) % 60 )); echo "Runtime: $hours:$minutes:$seconds (hh:mm:ss)"
Responder
Simplemente llame a times
sin argumentos al salir de su secuencia de comandos.
Con ksh
o zsh
, también puedes usar time
en su lugar. Con zsh
, time
también le dará la hora del reloj de pared además del usuario y sistema tiempo de CPU.
Para preservar el estado de salida de su secuencia de comandos, puede hacerlo:
ret=$?; times; exit "$ret"
O usted también puede agregar una trampa en EXIT
:
trap times EXIT
De esa manera, se llamará a las horas siempre que el shell salga y el estado de salida se conservará.
$ bash -c "trap times EXIT; : {1..1000000}" 0m0.932s 0m0.028s 0m0.000s 0m0.000s $ zsh -c "trap time EXIT; : {1..1000000}" shell 0.67s user 0.01s system 100% cpu 0.677 total children 0.00s user 0.00s system 0% cpu 0.677 total
También tenga en cuenta que todos los bash
, ksh
y zsh
tienen una $SECONDS
variable especial que se incrementa automáticamente cada segundo. Tanto en zsh
como en ksh93
, esa variable también se puede convertir en punto flotante (con typeset -F SECONDS
) para obtener más precisión. Esto es solo el tiempo del reloj de pared, no el tiempo de la CPU.
Comentarios
- Esa variable $ SECONDS es muy útil, ¡gracias!
- ¿Su enfoque elimina el efecto de los eventos temporales? – – Creo que su enfoque está cerca del
time
presentado anteriormente.- – Creo que el enfoquetimeit
presentado en el código MATLAB puede ser útil aquí. - Hola, @St é phane Chazelas. Encontré que
times
no ‘ da tiempo a la pared, ¿verdad? por ejemplo,bash -c 'trap times EXIT;sleep 2'
- @Binarus, sí, esa característica viene de ksh. Al contrario de ksh93 / zsh, además de que bash no es compatible con el punto flotante, ‘ también se divide en que, después de establecer SEGUNDOS en 0, cambiará a 1 de 0 a 1 segundo más tarde ( ya que solo considera el resultado de
time()
que solo tiene una granularidad de segundo completa). - @Binarus, no eso ‘ s entre 0 y 1. Si establece SEGUNDOS en 0 a las 12: 00: 00.000, cambiará a 1 un segundo después. Pero si lo configura en 12: 00: 00.999, cambiará a 1 un milisegundo más tarde. Pero sí, estoy de acuerdo en que probablemente no ‘ no importe mucho en la práctica si no ‘ no tiene una precisión inferior a un segundo de todos modos.
Responder
Llegué un poco tarde al tren, pero quería publicar mi solución (para una precisión inferior a un segundo ) en caso de que otros encuentren este hilo al buscar. La salida está en formato de días, horas, minutos y finalmente segundos:
res1=$(date +%s.%N) # do stuff in here res2=$(date +%s.%N) dt=$(echo "$res2 - $res1" | bc) dd=$(echo "$dt/86400" | bc) dt2=$(echo "$dt-86400*$dd" | bc) dh=$(echo "$dt2/3600" | bc) dt3=$(echo "$dt2-3600*$dh" | bc) dm=$(echo "$dt3/60" | bc) ds=$(echo "$dt3-60*$dm" | bc) LC_NUMERIC=C printf "Total runtime: %d:%02d:%02d:%02.4f\n" $dd $dh $dm $ds
Espero que alguien por ahí encuentra esto útil!
Comentarios
- Supongo que no hay otra forma (solo bash) excepto usando ‘ bc ‘ para hacer los cálculos. Por cierto, muy buen script;)
- Tenga cuidado con FreeBSD ‘ s
date
no admite precisión de menos de un segundo y solo agregará el literal «N
» a la marca de tiempo. - Muy buen script, pero mi bash no ‘ t manejar la subsegunda parte. También aprendí que / 1 en bc elimina efectivamente eso, así que agregué @ / 1 @ al cálculo de $ ds, ¡y ahora muestra cosas muy bien!
- bc admite módulo:
dt2=$(echo "$dt%86400" | bc)
. Solo digo … Por cierto, prefiero la formadt2=$(bc <<< "${dt}%86400")
pero esa ‘ es completamente personal. - No ‘ No sé nada sobre
bc
todavía, pero la división por86400
me hace desconfiar de la siguiente motivo: Hay días que no tienen 86400 segundos, por ejemplo, días en los que la hora cambia de DST a la hora normal y viceversa, o días con segundos bisiestos. Si esos días forman parte del período de tiempo que desea calcular, es decir, se encuentran entreres1
yres2
(incluidos estos valores), su secuencia de comandos probablemente fallará.
Respuesta
Mi método para bash
:
# Reset BASH time counter SECONDS=0 # # do stuff # ELAPSED="Elapsed: $(($SECONDS / 3600))hrs $((($SECONDS / 60) % 60))min $(($SECONDS % 60))sec"
Comentarios
- Esto muestra el tiempo transcurrido, pero no ‘ t mostrar » salida de grano fino como tiempo de procesador, tiempo de E / S » como se solicita en la pregunta.
- Aquellos que busquen una respuesta a la pregunta tal como se planteó probablemente encontrarán útil esta solución. Su comentario estaría mejor dirigido a la pregunta de OP.
Respuesta
Personalmente, me gusta envolver todos mis código de secuencia de comandos en alguna función «principal» como esta:
main () { echo running ... } # stuff ... # calling the function at the very end of the script time main
Observe lo fácil que es usar el comando time
en este escenario. Obviamente, no está midiendo el tiempo preciso, incluido el tiempo de análisis del script, pero lo encuentro lo suficientemente preciso en la mayoría de las situaciones.
Comentarios
- Excelente solución, no ‘ no requiere herramientas adicionales y es autónomo.
Respuesta
#!/bin/bash start=$(date +%s.%N) # HERE BE CODE end=$(date +%s.%N) runtime=$(python -c "print(${end} - ${start})") echo "Runtime was $runtime"
Sí, esto llama a Python, pero si puedes vivir con eso, entonces esta es una solución bastante agradable y concisa.
Comentarios
- Tenga en cuenta que ejecutar ese comando
python
en una subcapa y leer su salida llevará varios millones de nanosegundos en la mayoría de los sistemas actuales. Lo mismo ocurre condate
. - » Varios millones de nanosegundos » son varios milisegundos .La gente que mide el tiempo de los scripts de bash generalmente no está muy preocupada por eso (a menos que ejecuten varios miles de millones de scripts por megasegundo).
- Tenga en cuenta también que, incluso si el El cálculo se realiza dentro de un proceso de Python, los valores se recopilaron por completo antes de que se invocara Python. El tiempo de ejecución del script se medirá correctamente, sin los » millones de nanosegundos » sobrecarga.
-
time main
arriba es mucho más limpio …sí, podemos vivir con mucha degradación, pero ‘ es mucho mejor sin eso, ¡que ‘ sigan siendo ingenieros! -
$(echo $end - $start | bc)
hará lo mismo sin Python
Responder
Esta pregunta es bastante antigua, pero al tratar de encontrar mi forma favorita de hacerlo, este hilo salió muy alto … y me sorprende que nadie lo haya mencionado:
perf stat -r 10 -B sleep 1
«perf» es una herramienta de análisis de rendimiento incluida en el kernel en «tools / perf» y a menudo disponible para instalar como un paquete separado («perf» en CentOS y «linux-tools» en Debian / Ubuntu). La Wiki de perf del Kernal de Linux tiene mucha más información al respecto.
La ejecución de «perf stat» proporciona bastantes detalles, incluido el tiempo medio de ejecución. justo al final:
1.002248382 seconds time elapsed ( +- 0.01% )
Comentarios
- ¿Qué es
perf
? - @B Layer – edité mi respuesta t o dar una breve descripción de ‘ perf ‘.
-
perf stat
ahora se queja de » Es posible que no tenga permiso para recopilar estadísticas. » a menos que ejecute algunos comandos consudo
, lo que lo hace inútil en todos los escenarios en los que no ‘ no posee completamente la máquina de destino. - ¡Increíble, gracias! Una solución mucho más detallada que
time
que sugieren otros. En particular,time
no se aplica a la medición de soluciones de competencia de códigos (ya que no ‘ t tiempo de impresión en milisegundos o menos) , mientras que su solución lo hace.
Respuesta
Una pequeña función de shell que se puede agregar antes comandos para medir su tiempo:
tm() { local start=$(date +%s) $@ local exit_code=$? echo >&2 "took ~$(($(date +%s)-${start})) seconds. exited with ${exit_code}" return $exit_code }
Luego úselo en su secuencia de comandos, o en su línea de comando así:
tm the_original_command with all its parameters
Comentarios
- Valdría la pena agregar milisegundos, probé ilke
s=$(date +%s000)
, no estoy seguro si funciona. - @loretoparisi durante milisegundos, puede intentar
date +%s%N
. Consulta serverfault.com/questions/151109/… - Esto es genial, excepto que es más seguro. use
"$@"
Respuesta
#!/bin/csh #PBS -q glean #PBS -l nodes=1:ppn=1 #PBS -l walltime=10:00:00 #PBS -o a.log #PBS -e a.err #PBS -V #PBS -M [email protected] #PBS -m abe #PBS -A k4zhang-group START=$(date +%s) for i in {1..1000000} do echo 1 done END=$(date +%s) DIFF=$(echo "$END - $START" | bc) echo "It takes DIFF=$DIFF seconds to complete this task..."
Comentarios
- ¿Cómo es esto realmente diferente de las otras respuestas ya dadas que usan
date
antes y después el script y generar la diferencia entre ellos?
Responder
-
Solo use
time [any command]
. Por ejemplo:time sleep 1
dormirá durante un tiempo real (es decir, según el tiempo de un cronómetro) de ~ 1.000 a ~ 1.020 segundos, como se muestra aquí:$ time sleep 1 real 0m1.011s user 0m0.004s sys 0m0.000s
Qué cosa tan hermosa. Puede poner cualquier comando después de él, y genera el resultado en una forma agradable y legible por humanos. Realmente me gusta usarlo para cronometrar compilaciones. Ej .:
# time your "make" build time make # time your "Bazel" build time bazel build //path/to/some:target
… o para operaciones git que potencialmente pueden ser largo, para que pueda desarrollar expectativas mentales realistas:
# time how long it takes to pull from a massive repo when # I"m working from home during COVID-19. NB: `git pull` # is sooooo much slower than just pulling the one branch # you need with `git pull origin <branch>`, so just fetch # or pull what you need! time git pull origin master
-
Para necesidades de temporización más personalizadas donde es posible que deba manipular la salida o convertirla a otras formas, en bash , use la variable interna
$SECONDS
. Aquí «una demostración, que incluye la conversión de estos segundos a otras unidades, como minutos de punto flotante:Tenga en cuenta que
dt_min
se redondea de0.01666666666...
(1 segundo = esa cantidad de minutos) a0.017
en este caso, ya que «estoy usando la funciónprintf
para redondear. Lasleep 1;
parte de abajo es donde llamarías a tu script para que se ejecute y cronometra, pero estoy durmiendo solo 1 segundo por el bien de esta demostración.Comando:
start=$SECONDS; sleep 1; end=$SECONDS; dt_sec=$(( end - start )); \ dt_min=$(printf %.3f $(echo "$dt_sec/60" | bc -l)); \ echo "dt_sec = $dt_sec; dt_min = $dt_min"
Resultado:
dt_sec = 1; dt_min = 0.017
Relacionado:
- Leer más acerca de
bc
yprintf
en mi respuesta aquí: https://stackoverflow.com/questions/12722095/how-do-i-use-floating-point-division-in-bash/58479867#58479867 - Ya no recuerdo dónde aprendí por primera vez sobre el comando
time
, pero puede que haya sido de La respuesta de @Trudbert aquí mismo .
Responder
Usando solo bash también es posible medir y calcular la duración de tiempo para una parte del script de shell (o el tiempo transcurrido para todo el script):
start=$SECONDS ... # do time consuming stuff end=$SECONDS
ahora puede imprimir la diferencia:
echo "duration: $((end-start)) seconds."
si solo necesita una duración incremental, haga:
echo "duration: $((SECONDS-start)) seconds elapsed.."
También puede almacenar la duración en una variable:
let diff=end-start
Comentarios
- ^ ESTA es la respuesta, amigos. O más simplemente: $ SECONDS al final. Es ‘ una variable Bash INTEGRADA. Todas las otras respuestas solo están haciendo un trabajo adicional para reinventar esta rueda …
- Esto es solo una repetición de la respuesta anterior de Marks unix.stackexchange .com / a / 340156/155362 .
Respuesta
Función de temporización basada en SECONDS
, limitado solo a la granularidad de segundo nivel, no «utiliza ningún comando externo:
time_it() { local start=$SECONDS ts ec printf -v ts "%(%Y-%m-%d_%H:%M:%S)T" -1 printf "%s\n" "$ts Starting $*" "$@"; ec=$? printf -v ts "%(%Y-%m-%d_%H:%M:%S)T" -1 printf "%s\n" "$ts Finished $*; elapsed = $((SECONDS-start)) seconds" # make sure to return the exit code of the command so that the caller can use it return "$ec" }
Por ejemplo:
time_it sleep 5
da
2019-03-30_17:24:37 Starting sleep 5 2019-03-30_17:24:42 Finished sleep 5; elapsed = 5 seconds
Respuesta
¿Usar bash time incorporado?
time: time [-p] PIPELINE Execute PIPELINE and print a summary of the real time, user CPU time, and system CPU time spent executing PIPELINE when it terminates. The return status is the return status of PIPELINE. The `-p" option prints the timing summary in a slightly different format. This uses the value of the TIMEFORMAT variable as the output format.
Ejemplo:
TIMEFORMAT="The command took %Rs" time { sleep 0.1 }
Resultado:
The command took 0.108s
Respuesta
Aquí «una variación de Alex «s respuesta. Solo me importan los minutos y segundos, pero también quería que tuviera un formato diferente. Así que hice esto:
start=$(date +%s) end=$(date +%s) runtime=$(python -c "print "%u:%02u" % ((${end} - ${start})/60, (${end} - ${start})%60)")
Comentarios
- ¿Por qué el voto negativo? ¿Tengo un error?
- Usar
python
para ese cálculo también me parece un error, lo siento. Por qué la gente no puede ‘ simplemente llamar atime
es algo que me supera.
Responder
#!/bin/bash begin=$(date +"%s") Script termin=$(date +"%s") difftimelps=$(($termin-$begin)) echo "$(($difftimelps / 60)) minutes and $(($difftimelps % 60)) seconds elapsed for Script Execution."
Answer
La solución aceptada usando time
escribe en stderr
.
La solución que usa times
escribe en stdout
.
Las soluciones que utilizan $SECONDS
carecen de precisión inferior a un segundo.
Las otras soluciones implican llamar a programas externos como date
o perf
que no es eficiente.
Si está de acuerdo con alguno de estos, úselo.
Pero si necesita una solución eficiente para obtener los tiempos con precisión de milisegundos y los necesita en variables tales que el la salida original permanece inalterada puede combinar la sustitución del proceso con algunas redirecciones alrededor de time
que es mucho más rápido que llamar programas externos y permite redirecciones alrededor del script de contenedor de tiempo como en el comando / script original.
# Preparations: Cmd=vgs # example of a program to be timed which is writing to stdout and stderr Cmd="eval { echo stdout; echo stderr >&2; sleep 0.1; }" # other example; replace with your own TIMEFORMAT="%3R %3U %3S" # make time output easy to parse
Seleccione una de las siguientes variantes analizando la salida de time
apropiado para sus necesidades:
Variante más corta donde stdout
de $Cmd
está escrito en stderr
y nada para stdout
:
read Elapsed User System < <({ time $Cmd 2>&3; } 3>&2 2>&1 >&3)
Variante más larga que mantiene stdout
originales y stderr
separados uno del otro:
{ read Elapsed User System < <({ time $Cmd 2>&4; } 4>&2 2>&1 >&3); } 3>&1
La variante más complicada incluye cerrar los descriptores de archivos adicionales de modo que se llame a $Cmd
como si no tuviera este contenedor de tiempo y lvm
comandos como vgs
no se quejan de descriptores de archivos filtrados:
{ read Elapsed User System < <({ time $Cmd 2>&4 4>&-; } 4>&2 2>&1 >&3 3>&-); } 3>&1
Usted incluso puede simular una adición de punto flotante en bash
sin llamar a bc
que sería mucho más lento:
CPU=`printf %04d $((10#${User/.}+10#${System/.}))` # replace with your own postprocessing echo CPU ${CPU::-3}.${CPU: -3} s, Elapsed $Elapsed s >&2 # redirected independent of $Cmd
Posibles resultados con los dos ejemplos de $Cmd
en una CPU lenta:
File descriptor 3 (/dev/pts/1) leaked on vgs invocation. Parent PID 10756: bash File descriptor 4 (/dev/pts/1) leaked on vgs invocation. Parent PID 10756: bash VG #PV #LV #SN Attr VSize VFree b3 3 24 0 wz--n- 1.31t 1.19t CPU 0.052 s, Elapsed 0.056 s
O:
stdout stderr CPU 0.008 s, Elapsed 0.109 s