Jeg vil gerne vise afslutningstiden for et script.
Hvad jeg i øjeblikket gør er –
#!/bin/bash date ## echo the date at start # the script contents date ## echo the date at end
Dette viser bare tidspunktet for start og slutning af scriptet. Ville det være muligt at vise et fint kornet output som processortid / io tid osv.?
Kommentarer
- stackoverflow.com/questions/385408/ …
- Jeg tror, at det nuværende accepterede svar ikke rigtig er nok på grund af tidsmæssige udsving.
- @CiroSantilli 烏坎 事件 2016 六四 事件 法轮功 Jeg tror, din foreslåede tråd stadig ikke er tilstrækkelig til at eliminere effekten af tidsmæssige begivenheder.
- Også relateret: stackoverflow.com/questions/5152858/… eller noget unix.stackexchange.com/questions/334145 / …
- Der er en kommando, som du kan køre og derefter gange alle unix-kommandoer automatisk, har du glemt, hvordan du aktiverer?
Svar
Jus Brug ikke time
når du kalder scriptet:
time yourscript.sh
Kommentarer
- Dette output tre gange:
real
,user
ogsys
. For betydningerne af disse, se her . - og ” real ” er sandsynligvis, hvad folk vil vide – ” Real er tid til vægur – tid fra start til slut af opkaldet ”
- Er der en måde at fange stdout i en fil? For eksempel noget som
time $( ... ) >> out.txt
- Du kan også gøre dette til sekvenser af kommandoer på kommandolinjen, f.eks:
time (command1 && command2)
- Eller han kunne i sit script bare gøre: ekko $ SECONDS forudsat at det er bash ….
Svar
Hvis time
ikke er en mulighed,
start=`date +%s` stuff end=`date +%s` runtime=$((end-start))
Kommentarer
- Bemærk, at dette kun virker, hvis du ikke ‘ ikke har brug for præcision i sekund. For nogle anvendelser kan det være acceptabelt , for andre ikke. For lidt bedre præcision (du ‘ påkalder stadig
date
for eksempel, så du kan muligvis ved bedst få millisekundpræcision i praksis og sandsynligvis mindre), prøv at brugedate +%s.%N
. (%N
er nanosekunder siden hele andet sekund .) - @ChrisH Åh. Godt at påpege det; bash-aritmetisk udvidelse er kun heltal. Jeg ser to obvi ous muligheder enten grøft perioden i datoformatstrengen (og behandl den resulterende værdi som nanosekunder siden epoke), så brug
date +%s%N
, eller brug noget mere i stand sombc
for at beregne den faktiske køretid ud fra de to værdier som jwchew antyder. Alligevel føler jeg, at denne tilgang er en suboptimal måde at gøre det på;time
er betydeligt bedre, hvis det er tilgængeligt, af ovenstående grunde. - Bare installer
bc
, og gør derefter dette:runtime=$( echo "$end - $start" | bc -l )
- Hvis dit script tager flere minutter, skal du bruge:
echo "Duration: $((($(date +%s)-$start)/60)) minutes
- Yderligere til @ rubo77 kommentar, hvis dit script tager flere timer, skal du bruge
hours=$((runtime / 3600)); minutes=$(( (runtime % 3600) / 60 )); seconds=$(( (runtime % 3600) % 60 )); echo "Runtime: $hours:$minutes:$seconds (hh:mm:ss)"
Svar
Ring bare til times
uden argumenter, når du afslutter dit script.
Med ksh
eller zsh
, du kan også bruge time
i stedet. Med zsh
vil time
også give dig urets tid ud over brugeren og system CPU-tid.
For at bevare exit-status for dit script kan du gøre det:
ret=$?; times; exit "$ret"
Eller dig kan også tilføje en fælde på EXIT
:
trap times EXIT
På den måde kaldes tidspunkter, når skallen kommer ud og udgangsstatus bevares.
$ 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
Bemærk også, at alle bash
, ksh
og zsh
har en $SECONDS
speciel variabel, der automatisk forøges hvert sekund. I både zsh
og ksh93
kan variablen også gøres flydende punkt (med typeset -F SECONDS
) for at få mere præcision. Dette er kun vægurstid, ikke CPU-tid.
Kommentarer
- Denne $ SECONDS-variabel er meget nyttig, tak!
- Eliminerer din tilgang effekten af timelige begivenheder? – – Jeg tror, din tilgang er nær
time
-metoden, der blev præsenteret tidligere.- – Jeg trortimeit
tilgang præsenteret i MATLAB-kode kan være nyttig her. - Hej, @St é phane Chazelas. Jeg fandt
times
giver ‘ ikke muren tid, ikke? for eksempelbash -c 'trap times EXIT;sleep 2'
- @Binarus, ja, denne funktion kommer fra ksh. I modsætning til ksh93 / zsh udover bash, der ikke understøtter flydende punkt, er det ‘ også brudt i, at når du har indstillet SECONDS til 0, vil det skifte til 1 fra 0 til 1 sekund senere ( da det kun betragter resultatet af
time()
som kun har fuld anden granularitet). - @Binarus, ikke at ‘ s mellem 0 og 1. Hvis du indstiller SECONDS til 0 ved 12: 00: 00.000, ændres det til 1 et sekund senere. Men hvis du indstiller klokken 12.00: 00.999, ændres det til 1 en milisekund senere. Men ja, jeg er enig i, at det sandsynligvis ikke ‘ t betyder meget i praksis, hvis du ikke ‘ t alligevel har sub-sekunders præcision.
Svar
Jeg var lidt sent på vognen, men ville sende min løsning (for præcision under sekund ) hvis andre tilfældigvis snubler over denne tråd gennem søgning. Outputtet er i format af dage, timer, minutter og endelig sekunder:
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
Håber nogen derude finder dette nyttigt!
Kommentarer
- Jeg antager, at der ikke er nogen anden (kun bash) måde undtagen at bruge ‘ bc ‘ for at udføre beregningerne. BTW rigtig godt script;)
- Pas på, at FreeBSD ‘ s
date
understøtter ikke præcision under sekundet og tilføjer bare bogstavelig “N
” til tidsstemplet. - Meget flot script, men min bash ‘ t håndtere den sekundære del. Jeg lærte også, at / 1 i bc effektivt fjerner det, så jeg tilføjede @ / 1 @ til $ ds-beregningen, og det viser ting meget flot nu!
- bc understøtter modulo:
dt2=$(echo "$dt%86400" | bc)
. Bare siger … BTW Jeg foretrækker formularendt2=$(bc <<< "${dt}%86400")
men at ‘ er helt personlig. - Jeg don ‘ ikke ved noget om
bc
endnu, men delingen af86400
gør mig mistroisk mod følgende årsag: Der er dage, der ikke har 86400 sekunder, for eksempel dage, hvor tiden skiftes fra sommertid til normal tid og omvendt eller dage med spring sekunder. Hvis sådanne dage er en del af det tidsrum, du vil beregne, dvs. ligger mellemres1
ogres2
(inklusive disse værdier), er dit script vil sandsynligvis mislykkes.
Svar
Min metode til bash
:
# Reset BASH time counter SECONDS=0 # # do stuff # ELAPSED="Elapsed: $(($SECONDS / 3600))hrs $((($SECONDS / 60) % 60))min $(($SECONDS % 60))sec"
Kommentarer
- Dette viser forløbet tid, men det gør det ikke ‘ t viser ” finkornet output som processortid, I / O-tid ” som anmodet om i spørgsmålet.
- De, der søger efter et svar på det stillede spørgsmål, vil sandsynligvis finde denne løsning nyttig. Din kommentar ville være bedre adresseret til OPs-spørgsmålet.
Svar
Personligt kan jeg godt lide at pakke alle mine script kode i en eller anden “hoved” funktion som sådan:
main () { echo running ... } # stuff ... # calling the function at the very end of the script time main
Bemærk, hvor let det er at bruge kommandoen time
i dette scenarie. Det er klart, at du ikke måler den nøjagtige tid inklusive script-analyse-tid, men jeg finder det nøjagtigt i de fleste situationer.
Kommentarer
- Fantastisk løsning, kræver ikke ‘ ekstra værktøjer og er selvstændig.
Svar
#!/bin/bash start=$(date +%s.%N) # HERE BE CODE end=$(date +%s.%N) runtime=$(python -c "print(${end} - ${start})") echo "Runtime was $runtime"
Ja, dette kalder Python, men hvis du kan leve med det, er dette en ganske flot og kortfattet løsning.
Kommentarer
- Pas på, at kørsel af
python
kommandoen i en subshell og læsning af dens output vil tage flere millioner nanosekunder på de fleste nuværende systemer. Samme for at køredate
. - ” Flere millioner nanosekunder ” er flere millisekunder Folk, der timing bash-scripts, er normalt ikke meget bekymrede over det (medmindre de kører flere milliarder scripts pr. Megasekund).
- Bemærk også, at beregning foretages inden for en pythonproces, værdierne blev samlet samlet, inden python blev påberåbt. Eksekveringstiden for scriptet måles korrekt uden ” millioner af nanosekunder ” overhead.
-
time main
ovenfor er så meget mere rent …ja, vi kan leve med masser af nedbrydning, men det ‘ er bedre måde uden så lad ‘ forblive ingeniører! -
$(echo $end - $start | bc)
vil gøre det samme uden python
Svar
Dette spørgsmål er ret gammelt, men i forsøget på at finde min foretrukne måde at gøre det på kom denne tråd højt … og jeg overraskede ingen, der nævnte det:
perf stat -r 10 -B sleep 1
“perf” er et præstationsanalyseværktøj inkluderet i kernen under “tools / perf” og ofte tilgængeligt til installation som en separat pakke (“perf” i CentOS og “linux-tools” på Debian / Ubuntu). Linux Kernal perf Wiki har meget mere information om det.
At køre “perf stat” giver en hel del detaljer inklusive gennemsnitlig udførelsestid lige i slutningen:
1.002248382 seconds time elapsed ( +- 0.01% )
Kommentarer
- Hvad er
perf
? - @B Layer – redigeret mit svar t o give en kort beskrivelse af ‘ perf ‘.
-
perf stat
nu klager over ” Du har muligvis ikke tilladelse til at indsamle statistik. ” medmindre du kører nogle kommandoer medsudo
, hvilket gør det ubrugeligt i alle scenarier, hvor du ikke ‘ ikke helt ejer målmaskinen. - Fantastisk, tak! Meget mere finkornet løsning end
time
andre antyder. Isærtime
er ikke anvendelig til måling af kodekonkurrenceløsninger (da det ikke ‘ t udskrivningstid i millisekunder og mindre) , mens din løsning gør det.
Svar
En lille skalfunktion, der kan tilføjes før kommandoer til at måle deres tid:
tm() { local start=$(date +%s) $@ local exit_code=$? echo >&2 "took ~$(($(date +%s)-${start})) seconds. exited with ${exit_code}" return $exit_code }
Brug det derefter i dit script eller på din kommandolinje sådan:
tm the_original_command with all its parameters
Kommentarer
- Det ville være værd at tilføje millisekunder, prøvet ilke
s=$(date +%s000)
, ikke sikker hvis det virker. - @loretoparisi i milisekunder, kan du prøve
date +%s%N
. Se serverfault.com/questions/151109/… - Dette er fantastisk, undtagen mere sikkert brug
"$@"
Svar
#!/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..."
Kommentarer
- Hvordan adskiller dette sig virkelig fra de andre svar, der allerede er givet, som bruger
date
før og efter scriptet og output forskellen mellem dem?
Svar
-
Bare brug
time [any command]
. Eks:time sleep 1
vil sove i realtid (dvs. som tidsindstillet af et stopur) på ~ 1.000 til ~ 1.020 sek, som vist her:$ time sleep 1 real 0m1.011s user 0m0.004s sys 0m0.000s
Hvilken smuk ting. Du kan lægge en hvilken som helst kommando efter den, og den outputter resultatet i en flot, menneskelig læsbar form. Jeg kan godt lide at bruge det til timing builds. Eks:
# time your "make" build time make # time your "Bazel" build time bazel build //path/to/some:target
… eller til git-operationer, som potentielt kan være virkelig lang, så jeg kan udvikle realistiske mentale forventninger:
# 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
-
For mere tilpassede timingbehov hvor du muligvis skal manipulere output eller konvertere det til andre former, i bash , brug den interne
$SECONDS
variabel. Her “er en demo, herunder konvertering af disse sekunder til andre enheder, såsom minutter med flydende punkt:Bemærk, at
dt_min
afrundes fra0.01666666666...
(1 sekund = så mange minutter) til0.017
i dette tilfælde da jeg bruger funktionenprintf
til at afrunde.sleep 1;
-delen nedenfor er det sted, hvor du kalder dit script til at køre og tid, men jeg sover bare i 1 sekund i stedet for denne demo.Kommando:
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"
Output:
dt_sec = 1; dt_min = 0.017
Relateret:
- Læs mere om
bc
ogprintf
i mit svar her: https://stackoverflow.com/questions/12722095/how-do-i-use-floating-point-division-in-bash/58479867#58479867 - Jeg kan ikke huske, hvor jeg først lærte om kommandoen
time
, men det kan have været fra @Trudberts svar lige her .
Svar
Brug kun bash er det også muligt at måle og beregne tidsvarigheden for en del af shell-scriptet (eller den forløbne tid for hele scriptet):
start=$SECONDS ... # do time consuming stuff end=$SECONDS
du kan nu enten bare udskrive forskellen:
echo "duration: $((end-start)) seconds."
hvis du kun har brug for trinvis varighed, skal du gøre:
echo "duration: $((SECONDS-start)) seconds elapsed.."
Du kan også gemme varigheden i en variabel:
let diff=end-start
Kommentarer
- ^ DETTE er svaret folkens. Eller mere simpelt: $ SECONDS i slutningen. Det ‘ er en INDBYGGET Bash-variabel. Alle de andre svar gør bare ekstra arbejde for at genopfinde dette hjul …
- Dette er bare en gentagelse af Marks tidligere svar unix.stackexchange .com / a / 340156/155362 .
Svar
Timing-funktion baseret på SECONDS
, kun begrænset til granularitet på andet niveau, bruger ikke eksterne kommandoer:
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" }
For eksempel:
time_it sleep 5
giver
2019-03-30_17:24:37 Starting sleep 5 2019-03-30_17:24:42 Finished sleep 5; elapsed = 5 seconds
Svar
Brug bash-tid indbygget?
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.
Eksempel:
TIMEFORMAT="The command took %Rs" time { sleep 0.1 }
Output:
The command took 0.108s
Svar
Her “er en variation af Alex “s svar. Jeg er kun interesseret i minutter og sekunder, men jeg ville også have det formateret anderledes. Så jeg gjorde dette:
start=$(date +%s) end=$(date +%s) runtime=$(python -c "print "%u:%02u" % ((${end} - ${start})/60, (${end} - ${start})%60)")
Kommentarer
- Hvorfor downvote? Har jeg en fejl?
- Brug af
python
til denne beregning ser ligesom en fejl ud for mig, undskyld mand. Hvorfor folk kan ‘ ikke bare ringe tiltime
er uden for mig.
Svar
#!/bin/bash begin=$(date +"%s") Script termin=$(date +"%s") difftimelps=$(($termin-$begin)) echo "$(($difftimelps / 60)) minutes and $(($difftimelps % 60)) seconds elapsed for Script Execution."
Svar
Den accepterede løsning ved hjælp af time
skriver til stderr
.
Løsningen ved hjælp af times
skriver til stdout
.
Løsningerne, der bruger $SECONDS
, mangler præcision i sekund.
De andre løsninger involverer at kalde eksterne programmer som date
eller perf
som ikke er effektiv.
Hvis du har det godt med nogen af disse, skal du bruge det.
Men hvis du har brug for en effektiv løsning for at få tiden med millisekund præcision og har brug for dem i variabler sådan at original output forbliver uforstyrret du kan kombinere proceserstatning med nogle omdirigeringer omkring time
hvilket er meget hurtigere end at ringe eksterne programmer og tillader omdirigeringer omkring timing wrapper-scriptet som på den originale kommando / 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
Vælg en af følgende varianter, der analyserer output af time
passende til dine behov:
Korteste variant, hvor stdout
af $Cmd
skrives til stderr
og intet til stdout
:
read Elapsed User System < <({ time $Cmd 2>&3; } 3>&2 2>&1 >&3)
Længere variant, der holder original stdout
og stderr
adskilt af hinanden:
{ read Elapsed User System < <({ time $Cmd 2>&4; } 4>&2 2>&1 >&3); } 3>&1
Den mest komplicerede variant inkluderer lukning af de ekstra filbeskrivelser, så $Cmd
kaldes som om uden denne timingindpakning omkring den og lvm
kommandoer som vgs
klager ikke over lækkede filbeskrivelser:
{ read Elapsed User System < <({ time $Cmd 2>&4 4>&-; } 4>&2 2>&1 >&3 3>&-); } 3>&1
Dig kan endda falske en flydende tilføjelse i bash
uden at ringe til bc
hvilket ville være meget langsommere:
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
Mulige output med de to eksempler på $Cmd
på en langsom 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
Eller:
stdout stderr CPU 0.008 s, Elapsed 0.109 s