Aș dori să afișez timpul de finalizare a unui script.
Ceea ce fac în prezent este –
#!/bin/bash date ## echo the date at start # the script contents date ## echo the date at end
Aceasta arată doar ora de începere și de sfârșit a scriptului. este posibil să afișați o ieșire cu granulație fină, cum ar fi timpul procesorului / ora io, etc?
Comentarii
- stackoverflow.com/questions/385408/ …
- Cred că răspunsul curent acceptat nu este într-adevăr suficient din cauza fluctuațiilor temporale.
- @CiroSantilli 烏坎 事件 2016 六四 事件 法轮功 Cred că firul dvs. propus nu este încă suficient pentru a elimina efectul evenimentelor temporale.
- De asemenea, legat de: stackoverflow.com/questions/5152858/… sau oarecum unix.stackexchange.com/questions/334145 / …
- Există o comandă pe care o puteți rula și apoi cronometrează automat toate comenzile Unix, ați uitat cum să activați?
Răspuns
Jus nu utilizați time
când apelați scriptul:
time yourscript.sh
Comentarii
- Aceasta rezultă de trei ori:
real
,user
șisys
. Pentru semnificațiile acestora, consultați aici . - și ” real este probabil ceea ce oamenii vor să știe – ” Real este timpul ceasului de perete – timpul de la începutul până la sfârșitul apelului ”
- Există o modalitate de a captura stdout-ul într-un fișier? De exemplu, ceva de genul
time $( ... ) >> out.txt
- Puteți face acest lucru și secvențelor de comenzi de pe linia de comandă, de exemplu:
time (command1 && command2)
- Sau ar putea, în scenariul său, să facă: ecou $ SECONDS presupunând că este bash ….
Răspuns
Dacă time
nu este o opțiune,
start=`date +%s` stuff end=`date +%s` runtime=$((end-start))
Comentarii
- Rețineți că acest lucru funcționează numai dacă nu aveți ‘ de nevoie de precizie în secundă. Pentru unele utilizări care ar putea fi acceptabile , pentru alții nu. Pentru o precizie puțin mai bună (‘ invocați în continuare
date
de două ori, de exemplu, așa că s-ar putea la cel mai bun obțineți precizie de milisecundă în practică și probabil mai puțină), încercați să utilizațidate +%s.%N
. (%N
este nanosecunde din întreaga secundă .) - @ChrisH Oh. Bine arătându-l; expansiunea aritmetică bash este doar în întregime. Văd două obvi multe opțiuni; fie renunțați la perioadă în șirul de format de dată (și tratați valoarea rezultată ca nanosecunde din epocă), deci utilizați
date +%s%N
, sau folosiți ceva mai capabil cabc
pentru a calcula timpul real de rulare din cele două valori, așa cum sugerează jwchew. Totuși, consider că această abordare este un mod suboptim de a o face;time
este considerabil mai bun dacă este disponibil, din motivele prezentate mai sus. - Instalați doar
bc
și apoi faceți acest lucru:runtime=$( echo "$end - $start" | bc -l )
- Dacă scriptul dvs. durează câteva minute, utilizați:
echo "Duration: $((($(date +%s)-$start)/60)) minutes
- Mai departe de @ rubo77 comentariu, dacă scriptul dvs. durează câteva ore, utilizați
hours=$((runtime / 3600)); minutes=$(( (runtime % 3600) / 60 )); seconds=$(( (runtime % 3600) % 60 )); echo "Runtime: $hours:$minutes:$seconds (hh:mm:ss)"
Răspundeți
Apelați doar times
fără argumente la ieșirea din script.
Cu ksh
sau zsh
, puteți utiliza și time
. Cu zsh
, time
vă va oferi, de asemenea, ora ceasului de perete, în plus față de utilizator și system CPU time.
Pentru a păstra starea de ieșire a scriptului, îl puteți face:
ret=$?; times; exit "$ret"
Sau dvs. poate adăuga, de asemenea, o capcană pe EXIT
:
trap times EXIT
În acest fel, orele vor fi apelate de fiecare dată starea de ieșire va fi păstrată.
$ 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
De asemenea, rețineți că toate bash
, ksh
și zsh
au o variabilă specială $SECONDS
care se incrementează automat în fiecare secundă. Atât în zsh
cât și în ksh93
, acea variabilă poate fi transformată și în virgulă mobilă (cu typeset -F SECONDS
) pentru a obține mai multă precizie. Aceasta este doar ora ceasului de perete, nu timpul procesorului.
Comentarii
- Această variabilă $ SECONDS este foarte utilă, mulțumesc!
- Abordarea dvs. elimină efectul evenimentelor temporale? – – Cred că abordarea dvs. este aproape de
time
abordarea prezentată mai devreme.- – Cred că abordareatimeit
prezentată în codul MATLAB poate fi utilă aici. - Bună ziua, @St é phane Chazelas. Am găsit că
times
nu ‘ nu oferă timp de perete, nu? de exemplu,bash -c 'trap times EXIT;sleep 2'
- @Binarus, da, această caracteristică provine de la ksh. Spre deosebire de ksh93 / zsh, în afară de bash care nu suportă virgulă mobilă, ‘ s-a rupt și după ce ați setat SECONDS la 0, se va schimba la 1 de la 0 la 1 secundă mai târziu ( deoarece are în vedere doar rezultatul
time()
, care are doar o a doua granularitate completă). - @Binarus, nu că ‘ s între 0 și 1. Dacă setați SECONDS la 0 la 12: 00: 00.000, se va schimba la 1 o secundă mai târziu. Dar dacă îl setați la 12: 00: 00.999, acesta se va schimba la 1 milisecundă mai târziu. Dar da, sunt de acord că probabil ‘ nu contează prea mult în practică dacă ‘ oricum nu aveți precizie sub-secundă.
Răspuns
Am „întârziat la bandwagon, dar am vrut să postez soluția mea (pentru precizie în secundă) ) în cazul în care se întâmplă ca alții să dea peste acest fir prin căutare. Rezultatul este în format de zile, ore, minute și, în final, secunde:
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
Sper că cineva acolo găsește acest lucru util!
Comentarii
- Cred că nu există altă cale (numai bash) decât utilizarea ‘ bc ‘ pentru a face calculele. BTW script foarte bun;)
- Atenție la FreeBSD ‘ s
date
nu acceptă precizia sub-secundă și va adăuga doar literal „N
” la marcajul de timp. - Script foarte frumos, dar bash-ul meu nu ‘ t se ocupă de partea secundară. De asemenea, am aflat că / 1 în bc elimină efectiv acest lucru, așa că am adăugat @ / 1 @ la calculul $ ds și afișează lucruri foarte frumoase acum!
- bc acceptă modulul:
dt2=$(echo "$dt%86400" | bc)
. Spunând doar … BTW prefer formadt2=$(bc <<< "${dt}%86400")
, dar ‘ este complet personal. - Nu ‘ nu știu încă nimic despre
bc
, dar împărțirea cu86400
mă face să nu am încredere în următorul motiv: Există zile care nu au 86400 de secunde, de exemplu zile în care timpul este comutat de la ora de vară la ora normală și invers și zile cu secunde de salt. Dacă astfel de zile fac parte din intervalul de timp pe care doriți să îl calculați, adică sunt întreres1
șires2
(inclusiv aceste valori), scriptul dvs. probabil va eșua.
Răspuns
Metoda mea pentru bash
:
# Reset BASH time counter SECONDS=0 # # do stuff # ELAPSED="Elapsed: $(($SECONDS / 3600))hrs $((($SECONDS / 60) % 60))min $(($SECONDS % 60))sec"
Comentarii
- Aceasta arată timpul scurs, dar nu ‘ nu se afișează ” ieșire cu granulație fină precum timpul procesorului, timpul I / O ” așa cum a fost solicitat în întrebare.
- Cei care caută un răspuns la întrebarea așa cum este pusă vor găsi această soluție utilă. Comentariul dvs. ar fi mai bine adresat întrebării OP-urilor.
Răspuns
Personal, îmi place să înfășur toate codul scriptului în unele funcții „principale” de genul:
main () { echo running ... } # stuff ... # calling the function at the very end of the script time main
Observați cât de ușor este să folosiți comanda time
în acest scenariu. Evident, nu măsurați timpul precis, inclusiv timpul de analiză a scriptului, dar consider că este suficient de corect în majoritatea situațiilor.
Comentarii
- Soluție excelentă, ‘ nu necesită instrumente suplimentare și este autonom.
Răspuns
#!/bin/bash start=$(date +%s.%N) # HERE BE CODE end=$(date +%s.%N) runtime=$(python -c "print(${end} - ${start})") echo "Runtime was $runtime"
Da, apelează Python, dar dacă poți trăi cu asta, atunci aceasta este o soluție destul de drăguță, concisă.
Comentarii
- Feriți-vă că rularea acelei comenzi
python
într-un subshell și citirea ieșirii sale vor dura câteva milioane de nanosecunde pe majoritatea sistemelor actuale. Același lucru pentru rulareadate
. - ” Câteva milioane de nanosecunde ” este de câteva milisecunde . Persoanele care sincronizează scripturile bash nu sunt de obicei prea îngrijorate de acest lucru (cu excepția cazului în care rulează câteva miliarde de scripturi pe megasecundă).
- Observați, de asemenea, că, chiar dacă calculul se face în cadrul unui proces python, valorile au fost colectate în întregime înainte de a fi invocat python. Timpul de execuție al scriptului va fi măsurat corect, fără ” milioane de nanosecunde ” cheltuieli generale.
-
time main
de mai sus este mult mai curat …da, putem trăi cu o mulțime de degradări, dar ‘ e mult mai bine, fără ca ‘ să rămână ingineri! -
$(echo $end - $start | bc)
va face același lucru fără python
Răspunde
Această întrebare este destul de veche, dar în încercarea de a găsi modalitatea mea preferată de a o face, acest fir a apărut … și m-am mirat că nimeni nu a menționat-o:
perf stat -r 10 -B sleep 1
„perf” este un instrument de analiză a performanței inclus în kernel sub „tools / perf” și adesea disponibil pentru a fi instalat ca pachet separat („perf” în CentOS și „linux-tools” pe Debian / Ubuntu). Linux Kernal perf Wiki are mai multe informații despre aceasta.
Rularea „perf stat” oferă destul de multe detalii, inclusiv timpul mediu de execuție chiar la final:
1.002248382 seconds time elapsed ( +- 0.01% )
Comentarii
- Ce este
perf
? - @B Layer – a editat răspunsul meu t o dați o scurtă descriere a ‘ perf ‘.
-
perf stat
acum se plânge de ” Este posibil să nu aveți permisiunea de a colecta statistici. ” decât dacă executați unele comenzi cusudo
, ceea ce îl face inutil în toate scenariile în care nu ‘ dețineți complet mașina țintă. - Uimitor, mulțumesc! Soluție mult mai fină decât
time
sugerează alții. În special,time
nu se aplică soluțiilor de măsurare a concurenței codurilor (deoarece nu face ‘ timp de imprimare în milisecunde și mai puțin) , în timp ce soluția dvs. nu.
Răspuns
O funcție de shell mică care poate fi adăugată înainte comenzi pentru a-și măsura timpul:
tm() { local start=$(date +%s) $@ local exit_code=$? echo >&2 "took ~$(($(date +%s)-${start})) seconds. exited with ${exit_code}" return $exit_code }
Apoi folosiți-l în scriptul dvs. sau în linia de comandă astfel:
tm the_original_command with all its parameters
Comentarii
- Ar merita să adăugați milisecunde, încercat ilke
s=$(date +%s000)
, nu sunt sigur dacă funcționează. - @loretoparisi timp de milisecunde, puteți încerca
date +%s%N
. Consultați serverfault.com/questions/151109/… - Acest lucru este minunat, cu excepția faptului că este mai sigur utilizați
"$@"
Răspuns
#!/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..."
Comentarii
- Cum este acest lucru cu adevărat diferit de celelalte răspunsuri deja date care folosesc
date
înainte și după scriptul și ieșirea diferenței dintre ele?
Răspuns
-
Doar folosiți
time [any command]
. Ex:time sleep 1
va dormi pentru un timp real (adică, așa cum este cronometrat de un cronometru) de la ~ 1.000 la ~ 1.020 sec, așa cum se arată aici:$ time sleep 1 real 0m1.011s user 0m0.004s sys 0m0.000s
Ce lucru frumos. Puteți pune orice comandă după ea, iar rezultatul rezultă într-o formă drăguță, lizibilă de om. Îmi place foarte mult să-l folosesc pentru construcțiile de sincronizare. Ex:
# time your "make" build time make # time your "Bazel" build time bazel build //path/to/some:target
… sau pentru operații git care pot fi cu adevărat reale lung, astfel încât să pot dezvolta așteptări mentale realiste:
# 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
-
Pentru necesități de sincronizare mai personalizate unde poate fi necesar să manipulați ieșirea sau să o convertiți în alte forme, în bash , utilizați variabila
$SECONDS
internă. Aici „o demonstrație, inclusiv conversia acestor secunde în alte unități, cum ar fi minutele cu virgulă mobilă:Rețineți că
dt_min
se rotunjește de la0.01666666666...
(1 secundă = atât de multe minute) la0.017
în acest caz, deoarece „folosesc funcțiaprintf
pentru a rotunji. Parteasleep 1;
de mai jos este locul în care ați fi chemat scriptul să ruleze și să se aleagă, dar doar dorm doar 1 secundă, de dragul acestei demonstrații.Comandă:
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"
Ieșire:
dt_sec = 1; dt_min = 0.017
Related:
- Citiți mai multe despre
bc
șiprintf
în răspunsul meu aici: https://stackoverflow.com/questions/12722095/how-do-i-use-floating-point-division-in-bash/58479867#58479867 - Nu-mi amintesc de unde am aflat mai întâi despre comanda
time
, dar este posibil să fi fost de la Răspunsul @Trudbert chiar aici .
Răspuns
Folosind numai bash este de asemenea posibil să măsurați și să calculați durata de timp pentru o porțiune din scriptul shell (sau timpul scurs pentru întregul script):
start=$SECONDS ... # do time consuming stuff end=$SECONDS
acum puteți imprima diferența:
echo "duration: $((end-start)) seconds."
dacă aveți nevoie doar de durată incrementală, faceți:
echo "duration: $((SECONDS-start)) seconds elapsed.."
De asemenea, puteți stoca durata într-o variabilă:
let diff=end-start
Comentarii
- ^ Acesta este răspunsul, oameni buni. Sau mai simplu: $ SECONDS la final. ‘ este o variabilă Bash BUILT-IN. Toate celelalte răspunsuri fac doar o muncă suplimentară pentru a reinventa această roată …
- Aceasta este doar o repetare a răspunsului Marks anterior unix.stackexchange .com / a / 340156/155362 .
Răspuns
Funcția de sincronizare bazată pe SECONDS
, limitat doar la granularitatea de nivel secundar, nu folosește nicio comandă externă:
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" }
De exemplu:
time_it sleep 5
oferă
2019-03-30_17:24:37 Starting sleep 5 2019-03-30_17:24:42 Finished sleep 5; elapsed = 5 seconds
Răspuns
Utilizați 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.
Exemplu:
TIMEFORMAT="The command took %Rs" time { sleep 0.1 }
Ieșire:
The command took 0.108s
Răspuns
Aici „o variantă a lui Alex Răspunsul. Îmi pasă doar de minute și secunde, dar am vrut să fie formatat diferit. Așa că am făcut acest lucru:
start=$(date +%s) end=$(date +%s) runtime=$(python -c "print "%u:%02u" % ((${end} - ${start})/60, (${end} - ${start})%60)")
Comentarii
- De ce votul negativ? Am o eroare?
- Folosirea
python
pentru calculul respectiv mi se pare o eroare, scuze omule. De ce oamenii nu pot ‘ pur și simplu suna latime
este dincolo de mine.
Răspuns
#!/bin/bash begin=$(date +"%s") Script termin=$(date +"%s") difftimelps=$(($termin-$begin)) echo "$(($difftimelps / 60)) minutes and $(($difftimelps % 60)) seconds elapsed for Script Execution."
Răspuns
Soluția acceptată folosind time
scrie la stderr
.
Soluția care utilizează times
scrie la stdout
.
Soluțiile care utilizează $SECONDS
lipsesc precizie de secundă.
Celelalte soluții implică apelarea de programe externe precum date
sau perf
care nu este eficient.
Dacă sunteți bine cu oricare dintre acestea, utilizați-l.
Dar dacă aveți nevoie de o soluție eficientă pentru a obține timpii cu precizie milisecundă și au nevoie de ele în variabile astfel încât ieșirea originală rămâne netulburată puteți combina substituirea procesului cu unele redirecționări în jurul time
care este mult mai rapid decât apel programe externe și permite redirecționări în jurul scriptului de împachetare de sincronizare ca în comanda / scriptul 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
Selectați una dintre următoarele variante analizând rezultatul time
adecvat nevoilor dvs.:
Cea mai scurtă variantă în care se scrie stdout
din $Cmd
div id = „555ddc9905”>
și nimic pentrustdout
:
read Elapsed User System < <({ time $Cmd 2>&3; } 3>&2 2>&1 >&3)
Varianta mai lungă care păstrează stdout
și stderr
originale separate între ele:
{ read Elapsed User System < <({ time $Cmd 2>&4; } 4>&2 2>&1 >&3); } 3>&1
Cea mai complicată variantă include închiderea descriptorilor de fișiere suplimentare, astfel încât $Cmd
este chemat ca și cum ar fi fără acest înveliș de sincronizare în jurul său și comenzile precum vgs
nu se plâng de descriptorii de fișiere scurși:
{ read Elapsed User System < <({ time $Cmd 2>&4 4>&-; } 4>&2 2>&1 >&3 3>&-); } 3>&1
Tu poate chiar să falsifice o adăugare în virgulă mobilă în bash
fără a apela bc
ceea ce ar fi mult mai lent:
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
Ieșiri posibile cu cele două exemple de $Cmd
pe un procesor lent:
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
Sau:
stdout stderr CPU 0.008 s, Elapsed 0.109 s