Ik wil graag de voltooiingstijd van een script weergeven.
Wat ik momenteel doe is –
#!/bin/bash date ## echo the date at start # the script contents date ## echo the date at end
Dit toont alleen de tijd van begin en einde van het script. Zou dat zo zijn? mogelijk om een fijnmazige uitvoer weer te geven, zoals processortijd / io-tijd, enz.?
Reacties
- stackoverflow.com/questions/385408/ …
- Ik denk dat het huidige geaccepteerde antwoord niet echt voldoende is vanwege tijdelijke fluctuaties.
- @CiroSantilli 烏坎 事件 2016 六四 事件 法轮功 Ik denk dat je voorgestelde thread nog steeds niet voldoende is om het effect van tijdelijke gebeurtenissen te elimineren.
- Ook gerelateerd: stackoverflow.com/questions/5152858/… of enigszins unix.stackexchange.com/questions/334145 / …
- Er is een commando dat u kunt uitvoeren en vervolgens alle Unix-commandos automatisch verloopt, bent u vergeten hoe u dit inschakelt?
Antwoord
Jus t gebruik time
wanneer je het script aanroept:
time yourscript.sh
Reacties
- Dit wordt drie keer uitgevoerd:
real
,user
ensys
. Zie hier voor de betekenis ervan. - en ” real ” is waarschijnlijk wat mensen willen weten – ” Echt is de tijd van de wandklok – tijd van begin tot einde van het gesprek ”
- Is er een manier om de stdout in een bestand vast te leggen? Zoiets als
time $( ... ) >> out.txt
- U kunt dit ook doen met reeksen opdrachten op de opdrachtregel, bijvoorbeeld:
time (command1 && command2)
- Of hij kan, in zijn script, gewoon doen: echo $ SECONDS ervan uitgaande dat het bash is ….
Answer
Als time
geen optie is,
start=`date +%s` stuff end=`date +%s` runtime=$((end-start))
Opmerkingen
- Merk op dat dit alleen werkt als je ‘ geen precisie van minder dan een seconde nodig hebt. Voor sommige toepassingen kan dat acceptabel zijn , voor anderen niet. Voor een iets betere precisie (je ‘ roept nog steeds
date
twee keer aan, bijvoorbeeld, dus je kunt beste milliseconde precisie in de praktijk te krijgen, en waarschijnlijk minder), probeer dandate +%s.%N
te gebruiken. (%N
is nanoseconden sinds de hele seconde .) - @ChrisH Oh. Goed om erop te wijzen; bash rekenkundige uitbreiding is alleen integer. Ik zie twee obvi ous opties; laat de punt in de datumnotatiereeks achterwege (en behandel de resulterende waarde als nanoseconden sinds epoch), dus gebruik
date +%s%N
, of gebruik iets bekwamer zoalsbc
om de werkelijke looptijd te berekenen uit de twee waarden, zoals jwchew suggereert. Toch vind ik dat deze benadering een suboptimale manier is om het te doen;time
is aanzienlijk beter indien beschikbaar, om de hierboven uiteengezette redenen. - Installeer gewoon
bc
en doe dit:runtime=$( echo "$end - $start" | bc -l )
- Als uw script enkele minuten duurt, gebruik dan:
echo "Duration: $((($(date +%s)-$start)/60)) minutes
- Verder naar @ rubo77 opmerking, als uw script enkele uren duurt, gebruik dan
hours=$((runtime / 3600)); minutes=$(( (runtime % 3600) / 60 )); seconds=$(( (runtime % 3600) % 60 )); echo "Runtime: $hours:$minutes:$seconds (hh:mm:ss)"
Answer
Bel gewoon times
zonder argumenten bij het afsluiten van je script.
Met ksh
of zsh
, je kunt in plaats daarvan ook time
gebruiken. Met zsh
, time
geeft je naast de gebruiker en ook de wandkloktijd systeem CPU-tijd.
Om de exit-status van uw script te behouden, kunt u ervoor zorgen dat:
ret=$?; times; exit "$ret"
Of u kan ook een trap toevoegen op EXIT
:
trap times EXIT
Op die manier zullen tijden worden aangeroepen wanneer de shell wordt afgesloten en de exit-status blijft behouden.
$ 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
Merk ook op dat alle bash
, ksh
en zsh
hebben een $SECONDS
speciale variabele die automatisch elke seconde wordt opgehoogd. In zowel zsh
als ksh93
kan die variabele ook als zwevende komma worden gemaakt (met typeset -F SECONDS
) voor meer precisie. Dit is alleen wandkloktijd, geen CPU-tijd.
Opmerkingen
- Die $ SECONDS-variabele is erg handig, bedankt!
- Elimineert uw aanpak het effect van tijdelijke gebeurtenissen? – – Ik denk dat uw benadering in de buurt komt van de
time
-benadering die eerder is gepresenteerd.- – Ik denk dat detimeit
benadering gepresenteerd in MATLAB-code hier nuttig kan zijn. - Hallo, @St é phane Chazelas. Ik heb ontdekt dat
times
‘ geen tijd aan de muur geeft, toch? bijvoorbeeldbash -c 'trap times EXIT;sleep 2'
- @Binarus, ja, die functie komt van ksh. In tegenstelling tot ksh93 / zsh, behalve dat bash geen drijvende-komma ondersteunt, ‘ is ook onderbroken doordat nadat je SECONDS op 0 hebt ingesteld, het later zal veranderen in 1 van 0 tot 1 seconde ( aangezien het alleen rekening houdt met het resultaat van
time()
dat alleen volledige tweede granulariteit heeft). - @Binarus, niet dat ‘ s tussen 0 en 1. Als u SECONDEN op 0 instelt om 12: 00: 00.000, verandert dit een seconde later in 1. Maar als u het instelt op 12: 00: 00.999, verandert het een milliseconde later in 1. Maar ja, ik ben het ermee eens dat ‘ in de praktijk waarschijnlijk niet veel uitmaakt als je niet ‘ toch een precisie van minder dan een seconde hebt.
Answer
Ik “ben een beetje laat op de trein, maar wilde mijn oplossing posten (voor precisie van minder dan een seconde) ) voor het geval anderen toevallig deze thread tegenkomen tijdens het zoeken. De uitvoer is in de indeling dagen, uren, minuten en ten slotte seconden:
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
Hoop dat iemand daarbuiten vindt dit nuttig!
Reacties
- Ik denk dat er geen andere (alleen bash) manier is dan ‘ bc ‘ om de berekeningen uit te voeren. Trouwens echt goed script;)
- Pas op dat FreeBSD ‘ s
date
ondersteunt geen sub-seconde precisie en voegt gewoon de letterlijke “N
” toe aan het tijdstempel. - Heel mooi script, maar mijn bash doet het niet ‘ t omgaan met het subseconde deel. Ik heb ook geleerd dat / 1 in bc dat effectief verwijdert, dus heb ik @ / 1 @ toegevoegd aan de $ ds-berekening, en het toont nu heel mooie dingen!
- bc ondersteunt modulo:
dt2=$(echo "$dt%86400" | bc)
. Gewoon zeggen … Trouwens, ik geef de voorkeur aan de vormdt2=$(bc <<< "${dt}%86400")
maar dat ‘ is geheel persoonlijk. - Ik niet ‘ weet nog niets van
bc
, maar de deling door86400
maakt me wantrouwend voor de volgende reden: Er zijn dagen die geen 86400 seconden hebben, bijvoorbeeld dagen waarop de tijd wordt omgeschakeld van zomertijd naar normale tijd en vice versa, of dagen met schrikkelseconden. Als dergelijke dagen deel uitmaken van de tijdspanne die u wilt berekenen, dwz tussenres1
enres2
liggen (inclusief deze waarden), uw script zal waarschijnlijk mislukken.
Antwoord
Mijn methode voor bash
:
# Reset BASH time counter SECONDS=0 # # do stuff # ELAPSED="Elapsed: $(($SECONDS / 3600))hrs $((($SECONDS / 60) % 60))min $(($SECONDS % 60))sec"
Reacties
- Dit toont de verstreken tijd, maar niet ‘ t toon ” fijnkorrelige uitvoer zoals processortijd, I / O-tijd ” zoals gevraagd in de vraag.
- Wie op zoek is naar een antwoord op de gestelde vraag, zal deze oplossing waarschijnlijk nuttig vinden. Uw opmerking is beter gericht op de OP-vraag.
Antwoord
Persoonlijk wil ik al mijn scriptcode in een of andere “hoofd” -functie zoals:
main () { echo running ... } # stuff ... # calling the function at the very end of the script time main
Merk op hoe gemakkelijk het is om het time
commando te gebruiken in dit scenario. Het is duidelijk dat u “niet de exacte tijd meet, inclusief de tijd van de scriptontleding, maar ik vind het in de meeste situaties nauwkeurig genoeg.
Opmerkingen
- Geweldige oplossing, heeft geen ‘ geen extra tools nodig en staat op zichzelf.
Antwoord
#!/bin/bash start=$(date +%s.%N) # HERE BE CODE end=$(date +%s.%N) runtime=$(python -c "print(${end} - ${start})") echo "Runtime was $runtime"
Ja, dit roept Python aan, maar als je daarmee kunt leven, dan is dit best een aardige, beknopte oplossing.
Opmerkingen
- Pas op dat het uitvoeren van dat
python
-commando in een subshell en het lezen van de uitvoer ervan enkele miljoenen nanoseconden zal duren op de meeste huidige systemen. Hetzelfde voor het uitvoeren vandate
. - ” Enkele miljoenen nanoseconden ” is enkele milliseconden . Mensen die bash-scripts timen, maken zich daar meestal niet veel zorgen over (tenzij ze miljarden scripts per megaseconde uitvoeren).
- Merk ook op dat, zelfs als de berekening wordt gedaan in een python-proces, de waarden zijn volledig verzameld voordat python werd aangeroepen. De uitvoeringstijd van het script wordt correct gemeten, zonder de ” miljoenen nanoseconden ” overhead.
-
time main
hierboven is zoveel schoner …ja, we kunnen leven met veel degradatie, maar het is ‘ veel beter zonder dus laten ‘ s ingenieurs blijven! -
$(echo $end - $start | bc)
zal hetzelfde doen zonder python
Answer
Deze vraag is vrij oud, maar toen ik probeerde mijn favoriete manier te vinden om het te doen, kwam deze thread hoog … en het verbaasde me dat niemand het noemde:
perf stat -r 10 -B sleep 1
“perf” is een prestatieanalysetool opgenomen in de kernel onder “tools / perf” en vaak beschikbaar om te installeren als een apart pakket (“perf” in CentOS en “linux-tools” op Debian / Ubuntu). De Linux Kernal perf Wiki heeft veel meer informatie erover.
Het uitvoeren van “perf stat” geeft nogal wat details, inclusief de gemiddelde uitvoeringstijd helemaal aan het einde:
1.002248382 seconds time elapsed ( +- 0.01% )
Reacties
- Wat is
perf
? - @B Layer – bewerkt mijn antwoord t o geef een korte beschrijving van ‘ perf ‘.
-
perf stat
klaagt nu over ” Je hebt misschien geen toestemming om statistieken te verzamelen. ” tenzij je een aantal opdrachten uitvoert metsudo
, wat het nutteloos maakt in alle scenarios waarin u ‘ t niet volledig uw doelmachine bezit. - Geweldig, bedankt! Veel fijnmazigere oplossing dan
time
anderen suggereren. In het bijzonder istime
niet van toepassing op oplossingen voor het meten van codecompetities (aangezien het niet de ‘ afdruktijd in milliseconden en minder) , terwijl uw oplossing dat wel doet.
Answer
Een kleine shell-functie die eerder kan worden toegevoegd commandos om hun tijd te meten:
tm() { local start=$(date +%s) $@ local exit_code=$? echo >&2 "took ~$(($(date +%s)-${start})) seconds. exited with ${exit_code}" return $exit_code }
Gebruik het dan in je script, of op je commandoregel zoals:
tm the_original_command with all its parameters
Reacties
- Het zou de moeite waard zijn om milliseconden toe te voegen, probeerde ilke
s=$(date +%s000)
, niet zeker als het werkt. - @loretoparisi voor milliseconden, zou je
date +%s%N
kunnen proberen. Zie serverfault.com/questions/151109/… - Dit is geweldig, behalve veiliger gebruik
"$@"
Answer
#!/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..."
Reacties
- Hoe verschilt dit echt van de andere reeds gegeven antwoorden die
date
voor en na gebruiken het script en voer het verschil tussen hen uit?
Antwoord
-
Gewoon gebruik
time [any command]
. Vb:time sleep 1
slaapt gedurende een realtime (dwz: zoals getimed door een stopwatch) van ~ 1.000 tot ~ 1.020 sec, zoals hier getoond:$ time sleep 1 real 0m1.011s user 0m0.004s sys 0m0.000s
Wat een mooi ding. Je kunt er elk commando achter zetten, en het geeft het resultaat weer in een mooie, voor mensen leesbare vorm. Ik gebruik het echt graag voor timing-builds. Bijv .:
# time your "make" build time make # time your "Bazel" build time bazel build //path/to/some:target
… of voor git-bewerkingen die mogelijk echt kunnen zijn lang, zodat ik realistische mentale verwachtingen kan ontwikkelen:
# 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
-
Voor meer aangepaste timingbehoeften waar u mogelijk de uitvoer moet manipuleren of naar andere vormen moet converteren, in bash , gebruik de interne
$SECONDS
variabele. Hier “een demo, inclusief het converteren van deze seconden naar andere eenheden, zoals minuten met drijvende komma:Let op:
dt_min
wordt afgerond van0.01666666666...
(1 seconde = zoveel minuten) naar0.017
in dit geval omdat ik de functieprintf
gebruik om af te ronden. Hetsleep 1;
gedeelte hieronder is waar je “je script zou oproepen om uit te voeren en de tijd te nemen, maar ik” slaap gewoon voor 1 seconde omwille van deze demo.Commando:
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"
Uitvoer:
dt_sec = 1; dt_min = 0.017
Gerelateerd:
- Lees meer ongeveer
bc
enprintf
in mijn antwoord hier: https://stackoverflow.com/questions/12722095/how-do-i-use-floating-point-division-in-bash/58479867#58479867 - Ik weet niet meer waar ik voor het eerst hoorde over het
time
-commando, maar het kan afkomstig zijn van @Trudbert “s antwoord hier .
Antwoord
Gebruik alleen bash het is ook mogelijk om te meten en te berekenen de tijdsduur voor een deel van het shellscript (of de verstreken tijd voor het hele script):
start=$SECONDS ... # do time consuming stuff end=$SECONDS
u kunt nu ofwel gewoon het verschil afdrukken:
echo "duration: $((end-start)) seconds."
als je alleen een oplopende duur nodig hebt, doe dan:
echo "duration: $((SECONDS-start)) seconds elapsed.."
Je kunt de duur ook opslaan in een variabele:
let diff=end-start
Reacties
- ^ DIT is het antwoord mensen. Of eenvoudiger: $ SECONDS aan het einde. Het ‘ is een INGEBOUWDE Bash-variabele. Alle andere antwoorden doen gewoon extra werk om dit wiel opnieuw uit te vinden …
- Dit is slechts een herhaling van het eerdere antwoord van Marks unix.stackexchange .com / a / 340156/155362 .
Antwoord
Timingfunctie gebaseerd op SECONDS
, beperkt tot alleen granulariteit op het tweede niveau, “gebruikt geen externe opdrachten:
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" }
Bijvoorbeeld:
time_it sleep 5
geeft
2019-03-30_17:24:37 Starting sleep 5 2019-03-30_17:24:42 Finished sleep 5; elapsed = 5 seconds
Antwoord
Ingebouwde bash-tijd gebruiken?
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.
Voorbeeld:
TIMEFORMAT="The command took %Rs" time { sleep 0.1 }
Uitvoer:
The command took 0.108s
Antwoord
Hier is een variant van Alex “s antwoord. Ik geef alleen om minuten en seconden, maar ik wilde het ook anders opmaken. Dus ik deed dit:
start=$(date +%s) end=$(date +%s) runtime=$(python -c "print "%u:%02u" % ((${end} - ${start})/60, (${end} - ${start})%60)")
Reacties
- Waarom downvote? Heb ik een bug?
- Het gebruik van
python
voor die berekening lijkt mij ook een bug, sorry man. Waarom mensen ‘ niettime
kunnen bellen, is mij een raadsel.
Antwoord
#!/bin/bash begin=$(date +"%s") Script termin=$(date +"%s") difftimelps=$(($termin-$begin)) echo "$(($difftimelps / 60)) minutes and $(($difftimelps % 60)) seconds elapsed for Script Execution."
Antwoord
De geaccepteerde oplossing met time
schrijft naar stderr
.
De oplossing met times
schrijft naar stdout
.
De oplossingen die $SECONDS
gebruiken, missen precisie van minder dan een seconde.
De andere oplossingen omvatten het aanroepen van externe programmas zoals date
of perf
wat niet efficiënt is.
Als je het goed vindt met een van deze, gebruik het dan.
Maar als u een efficiënte oplossing nodig heeft om de tijden met milliseconde precisie en ze nodig hebben in variabelen zodat de originele uitvoer blijft ongestoord u kunt procesvervanging combineren met enkele omleidingen rond time
, wat veel sneller is dan bellen externe programmas en staat omleidingen rond het timing wrapper-script toe zoals bij het originele commando / script.
# 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
Selecteer een van de volgende varianten door de uitvoer van time
passend bij uw behoeften:
Kortste variant waarbij stdout
van $Cmd
wordt geschreven naar stderr
en niets aan stdout
:
read Elapsed User System < <({ time $Cmd 2>&3; } 3>&2 2>&1 >&3)
Langere variant die blijft origineel stdout
en stderr
scheiden van elkaar:
{ read Elapsed User System < <({ time $Cmd 2>&4; } 4>&2 2>&1 >&3); } 3>&1
De meest gecompliceerde variant omvat het sluiten van de extra bestandsbeschrijvingen zodat $Cmd
wordt aangeroepen alsof er geen timing-wrapper eromheen is en lvm
commandos zoals vgs
klagen niet over gelekte bestandsbeschrijvingen:
{ read Elapsed User System < <({ time $Cmd 2>&4 4>&-; } 4>&2 2>&1 >&3 3>&-); } 3>&1
U kan zelfs een drijvende-komma-toevoeging in bash
vervalsen zonder bc
aan te roepen, wat veel langzamer zou zijn:
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
Mogelijke uitvoer met de twee voorbeelden van $Cmd
op een langzame CPU:
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
Of:
stdout stderr CPU 0.008 s, Elapsed 0.109 s