Jeg vil vise fullføringstiden for et skript.
Det jeg for øyeblikket gjø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 slutt på skriptet. mulig å vise en finkornet utgang som prosessortid / io tid osv.?
Kommentarer
- stackoverflow.com/questions/385408/ …
- Jeg tror det nåværende aksepterte svaret egentlig ikke er nok på grunn av tidsmessige svingninger.
- @CiroSantilli 烏坎 事件 2016 六四 事件 法轮功 Jeg tror den foreslåtte tråden din fremdeles ikke er tilstrekkelig til å eliminere effekten av timelige hendelser.
- Også relatert: stackoverflow.com/questions/5152858/… eller noe unix.stackexchange.com/questions/334145 / …
- Det er en kommando du kan kjøre, og deretter ganger den alle unix-kommandoer automatisk, har du glemt hvordan du aktiverer?
Svar
Jus t bruk time
når du ringer til skriptet:
time yourscript.sh
Kommentarer
- Dette sendes ut tre ganger:
real
,user
ogsys
. For betydningen av disse, se her . - og » ekte » er sannsynligvis det folk vil vite – » Real er tid for klokke – tid fra start til slutt for samtalen »
- Er det en måte å fange stdout i en fil? For eksempel, noe sånt som
time $( ... ) >> out.txt
- Du kan også gjøre dette til kommandosekvenser på kommandolinjen, f.eks:
time (command1 && command2)
- Eller han kan bare gjøre i skriptet sitt: ekko $ SECONDS forutsatt at det er bash ….
Svar
Hvis time
ikke er et alternativ,
start=`date +%s` stuff end=`date +%s` runtime=$((end-start))
Kommentarer
- Merk at dette bare fungerer hvis du ikke trenger ‘ ikke trenger presisjon i andre sekund. For noen bruksområder kan det være akseptabelt , for andre ikke. For litt bedre presisjon (du ‘ fremkaller fortsatt
date
for eksempel to ganger, slik at du kan gå til best få millisekund presisjon i praksis, og sannsynligvis mindre), prøv å brukedate +%s.%N
. (%N
er nanosekunder siden hele andre .) - @ChrisH Å. Bra å påpeke det; bash-aritmetisk utvidelse er bare heltall. Jeg ser to obvi andre alternativer; enten grøft perioden i datoformatstrengen (og behandle den resulterende verdien som nanosekunder siden epoken), så bruk
date +%s%N
, eller bruk noe mer i stand sombc
for å beregne den faktiske kjøretiden fra de to verdiene som jwchew antyder. Likevel føler jeg at denne tilnærmingen er en suboptimal måte å gjøre det på;time
er betydelig bedre hvis tilgjengelig, av grunner som er skissert ovenfor. - Bare installer
bc
og gjør dette:runtime=$( echo "$end - $start" | bc -l )
- Hvis skriptet ditt tar flere minutter, bruk:
echo "Duration: $((($(date +%s)-$start)/60)) minutes
- Videre til @ rubo77 kommentar, hvis skriptet ditt tar flere timer, bruk
hours=$((runtime / 3600)); minutes=$(( (runtime % 3600) / 60 )); seconds=$(( (runtime % 3600) % 60 )); echo "Runtime: $hours:$minutes:$seconds (hh:mm:ss)"
Svar
Bare ring times
uten argumenter når du avslutter skriptet.
Med ksh
eller zsh
, kan du også bruke time
i stedet. Med zsh
vil time
også gi deg tid til veggklokken i tillegg til brukeren og system CPU-tid.
For å bevare utgangsstatusen for skriptet ditt, kan du gjøre det:
ret=$?; times; exit "$ret"
Eller du kan også legge til en felle på EXIT
:
trap times EXIT
På den måten vil tider bli kalt når skallet kommer ut og utgangsstatusen vil bli bevart.
$ 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
Legg også merke til at alle bash
, ksh
og zsh
har en $SECONDS
spesiell variabel som automatisk økes hvert sekund. I både zsh
og ksh93
kan den variabelen også gjøres flytende (med typeset -F SECONDS
) for å få mer presisjon. Dette er bare veggklokketid, ikke CPU-tid.
Kommentarer
- At $ SECONDS-variabelen er veldig nyttig, takk!
- Eliminerer din tilnærming effekten av timelige hendelser? – – Jeg tror tilnærmingen din er i nærheten av
time
tilnærming presentert tidligere.- – Jeg trortimeit
tilnærmingen presentert i MATLAB-kode kan være nyttig her. - Hei, @St é phane Chazelas. Jeg fant
times
gir ‘ ikke veggen tid, ikke sant? for eksempelbash -c 'trap times EXIT;sleep 2'
- @Binarus, ja, den funksjonen kommer fra ksh. I motsetning til ksh93 / zsh, ved siden av bash som ikke støtter flytende punkt, er det ‘ også brutt i at etter at du har satt SECONDS til 0, vil den endres til 1 fra 0 til 1 sekund senere ( da det bare vurderer resultatet av
time()
som bare har full andre granularitet). - @Binarus, ikke at ‘ s mellom 0 og 1. Hvis du setter SECONDS til 0 ved 12: 00: 00.000, vil det endres til 1 ett sekund senere. Men hvis du setter den klokken 12.00: 00.999, vil den endres til 1 milisekund senere. Men ja, jeg er enig i at det sannsynligvis ikke ‘ t betyr mye i praksis hvis du ikke har ‘ uansett. li>
Svar
Jeg var litt sent ute i vognen, men ville legge ut løsningen min (for presisjon i andre sekund ) hvis andre tilfeldigvis snubler over denne tråden gjennom søk. Utdataene er i format av dager, timer, minutter og til slutt 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åper noen der ute finner dette nyttig!
Kommentarer
- Jeg antar at det ikke er noen annen (bare bash) måte bortsett fra å bruke ‘ bc ‘ for å gjøre beregningene. BTW veldig bra skript;)
- Vær oppmerksom på at FreeBSD ‘ s
date
støtter ikke presisjon under sekund og vil bare legge til bokstavelig “N
” til tidsstempelet. - Veldig fint skript, men min bash gjør det ikke ‘ t håndtere den andre delen. Jeg lærte også at / 1 i bc effektivt striper det, så jeg la @ / 1 @ til $ ds-beregningen, og det viser ting veldig fine nå!
- bc støtter modulo:
dt2=$(echo "$dt%86400" | bc)
. Bare å si … BTW Jeg foretrekker skjemaetdt2=$(bc <<< "${dt}%86400")
men at ‘ er helt personlig. - Jeg don ‘ vet ikke noe om
bc
ennå, men delingen av86400
gjør meg mistroisk mot følgende årsak: Det er dager som ikke har 86400 sekunder, for eksempel dager der tiden byttes fra sommertid til normal tid og omvendt, eller dager med sprangsekunder. Hvis slike dager er en del av tidsperioden du vil beregne, dvs. er mellomres1
ogres2
(inkludert disse verdiene), skriptet ditt vil sannsynligvis mislykkes.
Svar
Min metode for 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øpt tid, men det ‘ t viser » finkornet utgang som prosessortid, I / O-tid » som forespurt i spørsmålet.
- De som søker etter svar på spørsmålet som stilles, vil sannsynligvis finne denne løsningen nyttig. Kommentaren din vil være bedre adressert til OPs-spørsmålet.
Svar
Personlig liker jeg å pakke inn alle mine skriptkode i noen «hoved» -funksjoner slik:
main () { echo running ... } # stuff ... # calling the function at the very end of the script time main
Legg merke til hvor enkelt det er å bruke kommandoen time
i dette scenariet. Åpenbart måler du ikke den nøyaktige tiden inkludert analysetid for skript, men jeg synes det er nøyaktig nok i de fleste situasjoner.
Kommentarer
- Flott løsning, krever ikke ‘ ekstra verktøy og er selvstendig.
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 kaller Python, men hvis du kan leve med det, er dette en ganske fin, kortfattet løsning.
Kommentarer
- Vær oppmerksom på at å kjøre den
python
kommandoen i en subshell og lese dens utdata vil ta flere millioner nanosekunder på de fleste nåværende systemer. Samme for å kjøredate
. - » Flere millioner nanosekunder » er flere millisekunder Folk timing bash-skript er vanligvis ikke veldig bekymret for det (med mindre de kjører flere milliarder skript per megasekund).
- Legg også merke til det, selv om beregning gjøres inne i en pythonprosess, verdiene ble samlet helt før python ble påkalt. Gjennomføringstiden for skriptet vil bli målt riktig, uten » millioner av nanosekunder » overhead.
-
time main
over er så mye mer rent …ja, vi kan leve med mye nedbrytning, men det ‘ er bedre uten å la ‘ være ingeniører! -
$(echo $end - $start | bc)
vil gjøre det samme uten python
Svar
Dette spørsmålet er ganske gammelt, men når jeg prøver å finne min favoritt måte å gjøre det på, kom denne tråden høyt … og jeg overrasket ingen nevnte det:
perf stat -r 10 -B sleep 1
«perf» er et ytelsesanalyseringsverktøy inkludert i kjernen under «tools / perf» og ofte tilgjengelig for installasjon som en egen pakke («perf» i CentOS og «linux-tools» på Debian / Ubuntu). Linux Kernal perf Wiki har mye mer informasjon om det.
Å kjøre «perf stat» gir ganske mange detaljer inkludert gjennomsnittlig utførelsestid rett på slutten:
1.002248382 seconds time elapsed ( +- 0.01% )
Kommentarer
- Hva er
perf
? - @B Layer – redigerte svaret mitt t o gi en kort beskrivelse av ‘ perf ‘.
-
perf stat
klager nå over » Du har kanskje ikke tillatelse til å samle inn statistikk. » med mindre du kjører noen kommandoer medsudo
, noe som gjør det ubrukelig i alle scenarier der du ikke ‘ t helt egen målmaskin. - Fantastisk, takk! Mye mer finkornet løsning enn
time
andre antyder. Spesielttime
er ikke aktuelt for måling av kodekonkurranseløsninger (da det ikke ‘ t utskriftstid i millisekunder og mindre) , mens løsningen din gjør det.
Svar
En liten skallfunksjon som kan legges til før kommandoer for å måle tiden deres:
tm() { local start=$(date +%s) $@ local exit_code=$? echo >&2 "took ~$(($(date +%s)-${start})) seconds. exited with ${exit_code}" return $exit_code }
Bruk den deretter i skriptet, eller på kommandolinjen slik:
tm the_original_command with all its parameters
Kommentarer
- Det ville være verdt å legge til millisekunder, prøvde ilke
s=$(date +%s000)
, ikke sikker hvis det fungerer. - @loretoparisi i milisekunder, kan du prøve
date +%s%N
. Se serverfault.com/questions/151109/… - Dette er flott, bortsett fra tryggere bruk
"$@"
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 er dette egentlig forskjellig fra de andre svarene som allerede er gitt som bruker
date
før og etter skriptet og skrive ut forskjellen mellom dem?
Svar
-
Bare bruk
time [any command]
. Eks:time sleep 1
vil sove i sanntid (dvs. som tidsbestemt av en stoppeklokke) på ~ 1.000 til ~ 1.020 sek, som vist her:$ time sleep 1 real 0m1.011s user 0m0.004s sys 0m0.000s
For en vakker ting. Du kan legge en hvilken som helst kommando etter den, og den viser resultatet i en fin, lesbar form. Jeg liker veldig godt å bruke den til timingbygging. Eks:
# time your "make" build time make # time your "Bazel" build time bazel build //path/to/some:target
… eller for git-operasjoner som potensielt kan være virkelig lenge, så jeg kan utvikle 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 mer tilpassede timingbehov der du kanskje trenger å manipulere utdata eller konvertere den til andre former, i bash , bruk den interne
$SECONDS
variabelen. Her «er en demo, inkludert konvertering av disse sekundene til andre enheter, for eksempel minutter med flytende punkt:Merk at
dt_min
blir avrundet fra0.01666666666...
(1 sekund = så mange minutter) til0.017
i dette tilfellet siden jeg brukerprintf
-funksjonen til å runde.sleep 1;
-delen nedenfor er der du vil kalle skriptet ditt til å kjøre og tid, men jeg sover bare i 1 sekund i stedet for denne demoens skyld.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"
Utgang:
dt_sec = 1; dt_min = 0.017
Relatert:
- Les mer om
bc
ogprintf
i mitt svar her: https://stackoverflow.com/questions/12722095/how-do-i-use-floating-point-division-in-bash/58479867#58479867 - Jeg husker ikke hvor jeg først lærte om
time
kommandoen lenger, men det kan ha vært fra @Trudbert «svar akkurat her .
Svar
Bruk bare bash er det også mulig å måle og beregne tidsvarigheten for en del av skallskriptet (eller forløpt tid for hele skriptet):
start=$SECONDS ... # do time consuming stuff end=$SECONDS
du kan nå enten bare skrive ut forskjellen:
echo "duration: $((end-start)) seconds."
hvis du bare trenger trinnvis varighet, gjør:
echo "duration: $((SECONDS-start)) seconds elapsed.."
Du kan også lagre varigheten i en variabel:
let diff=end-start
Kommentarer
- ^ DETTE er svaret folkens. Eller enklere: $ SECONDS på slutten. Det ‘ er en INNBYGGET Bash-variabel. Alle de andre svarene gjør bare ekstra arbeid for å finne opp dette hjulet på nytt …
- Dette er bare en repetisjon av Marks tidligere svar unix.stackexchange .com / a / 340156/155362 .
Svar
Timingsfunksjon basert på SECONDS
, begrenset til bare andre nivå granularitet, bruker 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
gir
2019-03-30_17:24:37 Starting sleep 5 2019-03-30_17:24:42 Finished sleep 5; elapsed = 5 seconds
Svar
Bruk bash tid innebygd?
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 }
Utgang:
The command took 0.108s
Svar
Her «er en variant av Alex «s svar. Jeg bryr meg bare om minutter og sekunder, men jeg ville også ha det formatert annerledes. Så jeg gjorde dette:
start=$(date +%s) end=$(date +%s) runtime=$(python -c "print "%u:%02u" % ((${end} - ${start})/60, (${end} - ${start})%60)")
Kommentarer
- Hvorfor nedstemmen? Har jeg en feil?
- Å bruke
python
for den beregningen ser ut som en feil for meg heller, beklager mann. Hvorfor folk ikke kan ‘ ikke bare ringetime
er utenfor meg.
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 aksepterte løsningen ved hjelp av time
skriver til stderr
.
Løsningen ved hjelp av times
skriver til stdout
.
Løsningene som bruker $SECONDS
mangler presisjon i andre sekund.
De andre løsningene innebærer å ringe eksterne programmer som date
eller perf
som ikke er effektiv.
Hvis du har det bra med noen av disse, bruk den.
Men hvis du trenger en effektiv løsning for å få tidene med millisekund presisjon og trenger dem til variabler slik at originalutdata forblir uforstyrret du kan kombinere prosesserstatning med noen omdirigeringer rundt time
som er mye raskere enn å ringe eksterne programmer og tillater omdirigeringer rundt tidsinnpakningsskriptet som på den opprinnelige kommandoen / skriptet.
# 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
Velg en av følgende varianter som analyserer utdata fra time
passende for deg behov:
Korteste variant der stdout
av $Cmd
skrives til stderr
og ingenting å stdout
:
read Elapsed User System < <({ time $Cmd 2>&3; } 3>&2 2>&1 >&3)
Lengre variant som holder original stdout
og stderr
atskilt fra hverandre:
{ read Elapsed User System < <({ time $Cmd 2>&4; } 4>&2 2>&1 >&3); } 3>&1
Den mest kompliserte varianten inkluderer å lukke de ekstra filbeskrivelsene slik at $Cmd
kalles som om uten denne tidsinnpakningen rundt den og lvm
kommandoer som vgs
klager ikke på lekkete filbeskrivere:
{ read Elapsed User System < <({ time $Cmd 2>&4 4>&-; } 4>&2 2>&1 >&3 3>&-); } 3>&1
Du kan til og med falske et flytende tillegg i bash
uten å ringe bc
som ville være mye tregere:
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 utganger med de to eksemplene på $Cmd
på en treg 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