Eu gostaria de exibir o tempo de conclusão de um script.
O que eu faço atualmente é –
#!/bin/bash date ## echo the date at start # the script contents date ## echo the date at end
Isso mostra apenas a hora de início e término do script. Seria possível exibir uma saída granulada, como tempo do processador / tempo io, etc?
Comentários
- stackoverflow.com/questions/385408/ …
- Acho que a resposta aceita atualmente não é realmente suficiente por causa das flutuações temporais.
- @CiroSantilli 烏坎 事件 2016 六四 事件 法轮功 Acho que o tópico proposto ainda não é suficiente para eliminar o efeito de eventos temporais.
- Também relacionado: stackoverflow.com/questions/5152858/… ou um pouco unix.stackexchange.com/questions/334145 / …
- Existe um comando que você pode executar e então ele cronometra todos os comandos unix automaticamente, esqueceu como habilitar?
Resposta
Jus t use time
ao chamar o script:
time yourscript.sh
Comentários
- Produz três vezes:
real
,user
esys
. Para saber seus significados, consulte aqui . - e ” real ” é provavelmente o que as pessoas querem saber – ” Real é a hora do relógio de parede – hora do início ao fim da chamada ”
- Existe uma maneira de capturar o stdout em um arquivo? Por exemplo, algo como
time $( ... ) >> out.txt
- Você também pode fazer isso com sequências de comandos na linha de comando, por exemplo:
time (command1 && command2)
- Ou ele poderia, em seu script, apenas fazer: echo $ SECONDS presumindo que seja bash ….
Resposta
Se time
não for uma opção,
start=`date +%s` stuff end=`date +%s` runtime=$((end-start))
Comentários
- Observe que isso só funciona se você não ‘ precisar de precisão de menos de um segundo. Para alguns usos, isso pode ser aceitável , para outros não. Para uma precisão ligeiramente melhor (você ‘ ainda está invocando
date
duas vezes, por exemplo, então você pode melhor obter precisão de milissegundos na prática, e provavelmente menos), tente usardate +%s.%N
. (%N
é nanossegundos desde o segundo inteiro .) - @ChrisH Oh. Bom apontar isso; a expansão aritmética bash é apenas para números inteiros. Vejo dois óbvios ous opções; elimine o período na string de formato de data (e trate o valor resultante como nanossegundos desde a época), então use
date +%s%N
ou use algo mais capaz comobc
para calcular o tempo de execução real a partir dos dois valores, como sugere o jwchew. Ainda assim, acho que essa abordagem é uma maneira subótima de fazer isso;time
é consideravelmente melhor se disponível, pelos motivos descritos acima. - Basta instalar
bc
e fazer o seguinte:runtime=$( echo "$end - $start" | bc -l )
- Se o seu script levar vários minutos, use:
echo "Duration: $((($(date +%s)-$start)/60)) minutes
- Na sequência de @ rubo77 comentário, se o seu script demorar várias horas, use
hours=$((runtime / 3600)); minutes=$(( (runtime % 3600) / 60 )); seconds=$(( (runtime % 3600) % 60 )); echo "Runtime: $hours:$minutes:$seconds (hh:mm:ss)"
Resposta
Basta chamar times
sem argumentos ao sair de seu script.
Com ksh
ou zsh
, você também pode usar time
. Com zsh
, time
também fornecerá a hora do relógio de parede, além do usuário e sistema tempo de CPU.
Para preservar o status de saída do seu script, você pode fazê-lo:
ret=$?; times; exit "$ret"
Ou você também pode adicionar uma armadilha em EXIT
:
trap times EXIT
Dessa forma, os horários serão chamados sempre que o shell sair e o status de saída será preservado.
$ 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
Observe também que todos os bash
, ksh
e zsh
têm uma $SECONDS
variável especial que é incrementada automaticamente a cada segundo. Em zsh
e ksh93
, essa variável também pode ser transformada em ponto flutuante (com typeset -F SECONDS
) para obter mais precisão. Este é apenas o tempo do relógio de parede, não o tempo da CPU.
Comentários
- Essa variável $ SECONDS é muito útil, obrigado!
- Sua abordagem elimina o efeito de eventos temporais? – Acho que sua abordagem está próxima da
time
abordagem apresentada anteriormente.- – Acho que a abordagemtimeit
apresentada no código MATLAB pode ser útil aqui. - Olá, @St é phane Chazelas. Descobri que
times
não ‘ dá tempo de parede, certo? por exemplo,bash -c 'trap times EXIT;sleep 2'
- @Binarus, sim, esse recurso vem de ksh. Ao contrário de ksh93 / zsh, além de bash não suportar ponto flutuante, ele ‘ também está quebrado, pois depois de definir SECONDS como 0, ele mudará para 1 de 0 a 1 segundo mais tarde ( uma vez que considera apenas o resultado de
time()
, que tem apenas uma segunda granularidade completa). - @Binarus, não que ‘ s entre 0 e 1. Se você definir SECONDS como 0 às 12: 00: 00.000, mudará para 1 um segundo depois. Mas se você defini-lo para 12h00,999, ele mudará para 1 um milissegundo depois. Mas sim, concordo que provavelmente não ‘ importa muito na prática se você não ‘ não tiver precisão inferior a um segundo de qualquer maneira.
Resposta
Estou um pouco atrasado para o movimento, mas queria postar minha solução (para precisão de sub-segundos ) caso outras pessoas encontrem este tópico durante a pesquisa. O resultado está no formato de dias, horas, minutos e, 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 alguém lá fora acha isso útil!
Comentários
- Acho que não há outra maneira (apenas bash), exceto usando ‘ bc ‘ para fazer os cálculos. BTW realmente bom script;)
- Cuidado com o FreeBSD ‘ s
date
não oferece suporte à precisão de subsegundos e apenas acrescentará literal “N
” ao carimbo de data / hora. - Script muito bom, mas meu bash não ‘ para lidar com a parte do subsegundo. Eu também aprendi que / 1 em bc efetivamente elimina isso, então adicionei @ / 1 @ ao cálculo de $ ds e ele exibe coisas muito boas agora!
- bc suporta módulo:
dt2=$(echo "$dt%86400" | bc)
. Apenas dizendo … BTW, eu prefiro a formadt2=$(bc <<< "${dt}%86400")
, mas que ‘ é totalmente pessoal. - Eu não ‘ não sei nada sobre
bc
ainda, mas a divisão por86400
me deixa desconfiado do seguinte motivo: Existem dias que não têm 86400 segundos, por exemplo, dias em que a hora é alterada de DST para a hora normal e vice-versa, ou dias com segundos intercalados. Se esses dias fizerem parte do intervalo de tempo que você deseja calcular, ou seja, entreres1
eres2
(incluindo esses valores), seu script provavelmente falhará.
Resposta
Meu método para bash
:
# Reset BASH time counter SECONDS=0 # # do stuff # ELAPSED="Elapsed: $(($SECONDS / 3600))hrs $((($SECONDS / 60) % 60))min $(($SECONDS % 60))sec"
Comentários
- Isso mostra o tempo decorrido, mas não ‘ t show ” saída refinada, como tempo do processador, tempo de E / S ” conforme solicitado na pergunta.
- Aqueles que procuram uma resposta para a questão apresentada provavelmente acharão esta solução útil. Seu comentário seria melhor endereçado à pergunta dos OPs.
Resposta
Pessoalmente, gosto de embrulhar todos os meus código de script em alguma função “principal” como:
main () { echo running ... } # stuff ... # calling the function at the very end of the script time main
Observe como é fácil usar o comando time
Neste cenário. Obviamente, você não está medindo o tempo preciso, incluindo o tempo de análise do script, mas acho que é preciso o suficiente na maioria das situações.
Comentários
- Ótima solução, não ‘ não requer ferramentas extras e é independente.
Resposta
#!/bin/bash start=$(date +%s.%N) # HERE BE CODE end=$(date +%s.%N) runtime=$(python -c "print(${end} - ${start})") echo "Runtime was $runtime"
Sim, isso chama Python, mas se você pode conviver com isso, então esta é uma solução muito boa e concisa.
Comentários
- Esteja ciente de que executar esse comando
python
em um subshell e ler sua saída levará vários milhões de nanossegundos na maioria dos sistemas atuais. O mesmo para executardate
. - ” Vários milhões de nanossegundos ” são vários milissegundos . Pessoas cronometrando scripts bash geralmente não se preocupam muito com isso (a menos que executem vários bilhões de scripts por megassegundo).
- Observe também que, mesmo que o o cálculo é feito dentro de um processo python, os valores foram inteiramente coletados antes de python ser chamado. O tempo de execução do script será medido corretamente, sem os ” milhões de nanossegundos ” sobrecarga.
-
time main
acima é muito mais limpo …sim, podemos viver com muita degradação, mas ‘ é muito melhor sem que ‘ continuem engenheiros! -
$(echo $end - $start | bc)
fará a mesma coisa sem python
Resposta
Esta pergunta é bastante antiga, mas ao tentar encontrar minha maneira favorita de fazer isso, este tópico surgiu alto … e estou surpreso que ninguém tenha mencionado isso:
perf stat -r 10 -B sleep 1
“perf” é uma ferramenta de análise de desempenho incluída no kernel em “tools / perf” e geralmente disponível para instalação como um pacote separado (“perf” no CentOS e “linux-tools” no Debian / Ubuntu). O Linux Kernal perf Wiki tem muito mais informações sobre ele.
A execução de “perf stat” fornece alguns detalhes, incluindo o tempo médio de execução bem no final:
1.002248382 seconds time elapsed ( +- 0.01% )
Comentários
- O que é
perf
? - @B Layer – editou minha resposta t o dê uma breve descrição de ‘ perf ‘.
-
perf stat
agora reclama sobre ” Você pode não ter permissão para coletar estatísticas. ” a menos que você execute alguns comandos comsudo
, o que o torna inútil em todos os cenários em que você não ‘ não possui completamente a máquina de destino. - Incrível, obrigado! Solução muito mais refinada do que
time
outras sugerindo. Em particular,time
não é aplicável para medir soluções de competição de código (uma vez que não ‘ tempo de impressão em milissegundos e menos) , enquanto sua solução sim.
Resposta
Uma pequena função shell que pode ser adicionada antes comandos para medir seu tempo:
tm() { local start=$(date +%s) $@ local exit_code=$? echo >&2 "took ~$(($(date +%s)-${start})) seconds. exited with ${exit_code}" return $exit_code }
Em seguida, use-o em seu script ou em sua linha de comando como:
tm the_original_command with all its parameters
Comentários
- Valeria a pena adicionar milissegundos, tentei ilke
s=$(date +%s000)
, não tenho certeza se funcionar. - @loretoparisi por milissegundos, você pode tentar
date +%s%N
. Consulte serverfault.com/questions/151109/… - Isso é ótimo, exceto mais seguro use
"$@"
Resposta
#!/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..."
Comentários
- Como isso é realmente diferente das outras respostas já fornecidas, que usam
date
antes e depois o script e mostrar a diferença entre eles?
Resposta
-
Apenas use
time [any command]
. Ex:time sleep 1
ficará hibernando por um tempo real (isto é: conforme cronometrado por um cronômetro) de ~ 1.000 a ~ 1.020 seg, conforme mostrado aqui:$ time sleep 1 real 0m1.011s user 0m0.004s sys 0m0.000s
Que coisa linda. Você pode colocar qualquer comando após ele, e ele exibe o resultado em um formato agradável e legível. Eu realmente gosto de usá-lo para cronometragem. Ex:
# time your "make" build time make # time your "Bazel" build time bazel build //path/to/some:target
… ou para operações git que podem ser realmente longo, para que eu possa desenvolver expectativas mentais 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 necessidades de tempo mais personalizadas onde você pode precisar manipular a saída ou convertê-la em outras formas, em bash , use a variável
$SECONDS
interna. Aqui está uma demonstração, incluindo a conversão desses segundos em outras unidades, como minutos de ponto flutuante:Observe que
dt_min
é arredondado de0.01666666666...
(1 segundo = tantos minutos) para0.017
neste caso, já que estou usando a funçãoprintf
para arredondar. Asleep 1;
parte abaixo é onde você chamaria seu script para executar e cronometrar, mas estou apenas dormindo por 1 segundo por causa desta demonstração.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:
- Leia mais sobre
bc
eprintf
em minha resposta aqui: https://stackoverflow.com/questions/12722095/how-do-i-use-floating-point-division-in-bash/58479867#58479867 - Não me lembro mais onde aprendi sobre o comando
time
, mas pode ter sido de Resposta de @Trudbert aqui .
Resposta
Usando somente bash também é possível medir e calcular a duração de uma parte do script de shell (ou o tempo decorrido para todo o script):
start=$SECONDS ... # do time consuming stuff end=$SECONDS
agora você pode apenas imprimir a diferença:
echo "duration: $((end-start)) seconds."
se você precisar apenas da duração incremental, faça:
echo "duration: $((SECONDS-start)) seconds elapsed.."
Você também pode armazenar a duração em uma variável:
let diff=end-start
Comentários
- ^ ESTA é a resposta, pessoal. Ou mais simplesmente: $ SECONDS no final. É ‘ uma variável Bash INTEGRADA. Todas as outras respostas estão apenas fazendo um trabalho extra para reinventar esta roda …
- Esta é apenas uma repetição da resposta anterior de Marcos unix.stackexchange .com / a / 340156/155362 .
Resposta
Função de tempo baseada em SECONDS
, limitado à granularidade de segundo nível apenas, não usa nenhum 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 exemplo:
time_it sleep 5
dá
2019-03-30_17:24:37 Starting sleep 5 2019-03-30_17:24:42 Finished sleep 5; elapsed = 5 seconds
Resposta
Usar bash time builtin?
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.
Exemplo:
TIMEFORMAT="The command took %Rs" time { sleep 0.1 }
Resultado:
The command took 0.108s
Resposta
Aqui “uma variação de Alex “s resposta. Eu só me importo com minutos e segundos, mas também queria formatado de forma diferente. Então fiz isso:
start=$(date +%s) end=$(date +%s) runtime=$(python -c "print "%u:%02u" % ((${end} - ${start})/60, (${end} - ${start})%60)")
Comentários
- Por que o voto negativo? Tenho um bug?
- Usar
python
para esse cálculo também parece um bug para mim, desculpe cara. Por que as pessoas podem ‘ t apenas ligar paratime
está além da minha compreensão.
Resposta
#!/bin/bash begin=$(date +"%s") Script termin=$(date +"%s") difftimelps=$(($termin-$begin)) echo "$(($difftimelps / 60)) minutes and $(($difftimelps % 60)) seconds elapsed for Script Execution."
Resposta
A solução aceita usando time
grava em stderr
.
A solução usando times
grava em stdout
.
As soluções que usam $SECONDS
não têm precisão de sub-segundos.
As outras soluções envolvem chamar programas externos como date
ou perf
que não é eficiente.
Se você estiver satisfeito com algum desses, use-o.
Mas se você precisar de uma solução eficiente para obter os tempos com precisão de milissegundos e precisa deles em variáveis de modo que a saída original permanece inalterada você pode combinar a substituição do processo com alguns redirecionamentos em torno de time
, o que é muito mais rápido do que chamar programas externos e permite redirecionamentos em torno do script de wrapper de tempo como no 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
Selecione uma das seguintes variantes analisando a saída de time
apropriado para suas necessidades:
Variante mais curta em que stdout
de $Cmd
é gravado em stderr
e nada a stdout
:
read Elapsed User System < <({ time $Cmd 2>&3; } 3>&2 2>&1 >&3)
Variante mais longa que mantém originais stdout
e stderr
separados uns dos outros:
{ read Elapsed User System < <({ time $Cmd 2>&4; } 4>&2 2>&1 >&3); } 3>&1
A variante mais complicada inclui o fechamento dos descritores de arquivo extras, de forma que $Cmd
seja chamado sem este wrapper de tempo em torno dele e lvm
comandos como vgs
não reclamam sobre descritores de arquivo vazados:
{ read Elapsed User System < <({ time $Cmd 2>&4 4>&-; } 4>&2 2>&1 >&3 3>&-); } 3>&1
Você pode até simular uma adição de ponto flutuante em bash
sem chamar bc
, o que seria muito mais 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
Possíveis saídas com os dois exemplos de $Cmd
em uma 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
Ou:
stdout stderr CPU 0.008 s, Elapsed 0.109 s