Jag vill visa slutdatum för ett skript.
Vad jag för närvarande gör är –
#!/bin/bash date ## echo the date at start # the script contents date ## echo the date at end
Detta visar bara tidpunkten för manusens början och slut. Skulle det vara möjligt att visa en finkornig utgång som processortid / io-tid, etc?
Kommentarer
- stackoverflow.com/questions/385408/ …
- Jag tror att det nuvarande accepterade svaret inte är tillräckligt på grund av tidsvariationer.
- @CiroSantilli 烏坎 事件 2016 六四 事件 法轮功 Jag tror att din föreslagna tråd fortfarande inte är tillräcklig för att eliminera effekten av tidsmässiga händelser.
- Även relaterad: stackoverflow.com/questions/5152858/… eller något unix.stackexchange.com/questions/334145 / …
- Det finns ett kommando som du kan köra och sedan tider det alla unix-kommandon automatiskt, glömde hur man aktiverar?
Svar
Jus använd time
när du ringer till skriptet:
time yourscript.sh
Kommentarer
- Detta matas ut tre gånger:
real
,user
ochsys
. För betydelserna av dessa, se här . - och ” real ” är förmodligen vad folk vill veta – ” Real är tid för väggklocka – tid från början till slut för samtalet ”
- Finns det ett sätt att fånga in stdout i en fil? Till exempel något som
time $( ... ) >> out.txt
- Du kan också göra detta för sekvenser av kommandon på kommandoraden, t.ex.:
time (command1 && command2)
- Eller så kan han bara göra i sitt manus: echo $ SECONDS förutsatt att det är bash ….
Svar
Om time
inte är ett alternativ,
start=`date +%s` stuff end=`date +%s` runtime=$((end-start))
Kommentarer
- Observera att det här bara fungerar om du inte behöver ’ t behöver precision under andra sekunden. För vissa användningar kan det vara acceptabelt , för andra inte. För lite bättre precision (du ’ åberopar fortfarande
date
två gånger, till exempel, så kan du till bästa få millisekundprecision i praktiken, och förmodligen mindre), försök att användadate +%s.%N
. (%N
är nanosekunder sedan hela den andra .) - @ChrisH Åh. Bra att påpeka det; bash-aritmetisk expansion är endast heltal. Jag ser två obvi andra alternativ; antingen dike perioden i datumformatsträngen (och behandla det resulterande värdet som nanosekunder sedan epoken), så använd
date +%s%N
, eller använd något mer kapabelt sombc
för att beräkna den faktiska körtiden från de två värdena som jwchew föreslår. Ändå tycker jag att detta tillvägagångssätt är ett suboptimalt sätt att göra det;time
är betydligt bättre om det är tillgängligt, av skäl som beskrivs ovan. - Installera bara
bc
och gör sedan detta:runtime=$( echo "$end - $start" | bc -l )
- Om ditt skript tar flera minuter, använd:
echo "Duration: $((($(date +%s)-$start)/60)) minutes
- Vidare till @ rubo77 kommentera, om ditt skript tar flera timmar, använd
hours=$((runtime / 3600)); minutes=$(( (runtime % 3600) / 60 )); seconds=$(( (runtime % 3600) % 60 )); echo "Runtime: $hours:$minutes:$seconds (hh:mm:ss)"
Svar
Ring bara times
utan argument när du avslutar skriptet.
Med ksh
eller zsh
, du kan också använda time
istället. Med zsh
, time
ger dig också tid för väggklockan förutom användaren och system CPU-tid.
För att bevara utgångsstatus för ditt skript kan du göra det:
ret=$?; times; exit "$ret"
Eller du kan också lägga till en fälla på EXIT
:
trap times EXIT
På det sättet kommer tider att kallas när skalet går ut och utgångsstatusen bevaras.
$ 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
Observera också att alla bash
, ksh
och zsh
har en $SECONDS
specialvariabel som automatiskt ökas varje sekund. I både zsh
och ksh93
kan variabeln också göras flytande (med typeset -F SECONDS
) för att få mer precision. Detta är bara tid för väggklocka, inte CPU-tid.
Kommentarer
- Den variabeln $ SECONDS är väldigt användbar, tack!
- Eliminerar din inställning effekten av tidsmässiga händelser? – – Jag tror att ditt tillvägagångssätt är nära
time
tillvägagångssätt som presenterades tidigare.- – Jag tror atttimeit
-metoden som presenteras i MATLAB-koden kan vara användbar här. - Hej, @St é fasan Chazelas. Jag hittade att
times
ger ’ inte väggtid, eller hur? till exempelbash -c 'trap times EXIT;sleep 2'
- @Binarus, ja, den funktionen kommer från ksh. I motsats till ksh93 / zsh, bredvid bash som inte stöder flytpunkt, är det ’ också brutet genom att när du har ställt SECONDS till 0, kommer det att ändras till 1 från 0 till 1 sekund senare ( eftersom det bara tar hänsyn till resultatet av
time()
som bara har full andra granularitet). - @Binarus, inte att ’ s mellan 0 och 1. Om du ställer in SECONDS till 0 vid 12: 00: 00.000 ändras det till 1 en sekund senare. Men om du ställer in klockan 12.00: 00.999 ändras det till en milisekund senare. Men ja, jag håller med om att det troligtvis inte ’ betyder något i praktiken om du inte ’ inte har någon sekunders precision ändå.
Svar
Jag var lite sen till vagnen, men ville lägga upp min lösning (för precision under sekunden ) om andra råkar stöta på den här tråden genom sökning. Utdata är i format av dagar, timmar, minuter och slutligen 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
Hoppas någon där ute tycker det är användbart!
Kommentarer
- Jag antar att det inte finns något annat (endast bash) sätt än att använda ’ bc ’ för att göra beräkningarna. BTW riktigt bra skript;)
- Var uppmärksam på att FreeBSD ’ s
date
stöder inte sekunders precision och kommer bara att lägga till bokstavligt “N
” till tidsstämpeln. - Mycket trevligt skript, men min bash ’ t hantera den andra delen. Jag lärde mig också att / 1 i bc effektivt tar bort det, så jag lade till @ / 1 @ i $ ds-beräkningen, och det visar saker mycket trevligt nu!
- bc stöder modulo:
dt2=$(echo "$dt%86400" | bc)
. Jag säger bara … BTW Jag föredrar formuläretdt2=$(bc <<< "${dt}%86400")
men att ’ är helt personligt. - Jag don ’ vet inte någonting om
bc
än, men delningen av86400
gör mig misstro mot följande anledning: Det finns dagar som inte har 86400 sekunder, till exempel dagar där tiden byts från sommartid till normal tid och vice versa, eller dagar med språngsekunder. Om sådana dagar är en del av det tidsintervall du vill beräkna, dvs. ligger mellanres1
ochres2
(inklusive dessa värden), ditt skript kommer troligen att misslyckas.
Svar
Min metod för bash
:
# Reset BASH time counter SECONDS=0 # # do stuff # ELAPSED="Elapsed: $(($SECONDS / 3600))hrs $((($SECONDS / 60) % 60))min $(($SECONDS % 60))sec"
Kommentarer
- Detta visar förfluten tid, men ’ t visar ” finkornig utgång som processortid, I / O-tid ” som begärts i frågan.
- De som letar efter ett svar på den ställda frågan kommer sannolikt att hitta den här lösningen användbar. Din kommentar skulle vara bättre adresserad till OPs-frågan.
Svar
Personligen gillar jag alla mina skriptkod i någon ”huvud” -funktion som så:
main () { echo running ... } # stuff ... # calling the function at the very end of the script time main
Lägg märke till hur enkelt det är att använda kommandot time
i detta scenario. Uppenbarligen mäter du inte den exakta tiden inklusive tid för skriptanalys, men jag tycker att det är tillräckligt exakt i de flesta situationer.
Kommentarer
- Bra lösning, kräver ’ inte extra verktyg och är fristående.
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, det här kallar Python, men om du kan leva med det är det här en ganska trevlig, kortfattad lösning.
Kommentarer
- Var uppmärksam på att det att ta det
python
-kommandot i en subshell och läsa utdata tar flera miljoner nanosekunder på de flesta nuvarande system. div id = ”33e4a5674d”>
.
time main
ovan är så mycket renare …ja, vi kan leva med mycket nedbrytning men det ’ är bättre utan så låt ’ vara ingenjörer! $(echo $end - $start | bc)
kommer att göra samma sak utan python Svar
Den här frågan är ganska gammal men när jag försökte hitta mitt favorit sätt att göra det kom den här tråden upp högt … och jag förvånade mig att ingen nämnde den:
perf stat -r 10 -B sleep 1
”perf” är ett prestandaanalyseringsverktyg som ingår i kärnan under ”tools / perf” och ofta tillgängligt för installation som ett separat paket (”perf” i CentOS och ”linux-tools” på Debian / Ubuntu). Linux Kernal perf Wiki har mycket mer information om det.
Att köra ”perf stat” ger en hel del detaljer inklusive genomsnittlig körtid precis i slutet:
1.002248382 seconds time elapsed ( +- 0.01% )
Kommentarer
- Vad är
perf
? - @B Layer – redigerat mitt svar t o ge en kort beskrivning av ’ perf ’.
-
perf stat
klagar nu på ” Du kanske inte har behörighet att samla in statistik. ” om du inte kör några kommandon medsudo
, vilket gör det värdelöst i alla scenarier där du inte ’ t helt egen målmaskin. - Fantastiskt, tack! Sätt mer finkornig lösning än
time
andra föreslår. I synnerhet ärtime
inte tillämplig på mätning av kodkonkurrenslösningar (eftersom den inte ’ t skriver ut i millisekunder och mindre) medan din lösning gör det.
Svar
En liten skalfunktion som kan läggas till innan kommandon för att mäta sin tid:
tm() { local start=$(date +%s) $@ local exit_code=$? echo >&2 "took ~$(($(date +%s)-${start})) seconds. exited with ${exit_code}" return $exit_code }
Använd den sedan i ditt skript eller på din kommandorad så:
tm the_original_command with all its parameters
Kommentarer
- Det vore värt att lägga till millisekunder, försökte ilke
s=$(date +%s000)
, inte säker om det fungerar. - @loretoparisi under milsekunder kan du prova
date +%s%N
. Se serverfault.com/questions/151109/… - Det här är bra, utom säkrare använd
"$@"
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
- Hur skiljer sig detta egentligen från de andra svar som redan ges som använder
date
före och efter skriptet och mata ut skillnaden mellan dem?
Svar
-
Bara använd
time [any command]
. Ex:time sleep 1
kommer att sova i realtid (dvs. enligt en stoppur) på ~ 1.000 till ~ 1.020 sek, som visas här:$ time sleep 1 real 0m1.011s user 0m0.004s sys 0m0.000s
Vilken vacker sak. Du kan lägga valfritt kommando efter det och resultatet ger resultatet i en trevlig, läsbar form. Jag gillar verkligen att använda den för att bygga timing. Ex:
# time your "make" build time make # time your "Bazel" build time bazel build //path/to/some:target
… eller för git-operationer som potentiellt kan vara riktigt lång så att jag kan utveckla realistiska mentala förväntningar:
# 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
-
För mer anpassade tidsbehov där du kan behöva manipulera utdata eller konvertera den till andra former, i bash , använd den interna variabeln
$SECONDS
. Här ”är en demo, inklusive konvertering av dessa sekunder till andra enheter, till exempel flytande punktminuter:Observera att
dt_min
avrundas från0.01666666666...
(1 sekund = så många minuter) till0.017
i det här fallet eftersom jag använderprintf
-funktionen för att runda.sleep 1;
-delen nedan är där du skulle kalla ditt skript för att köra och tid, men jag sover bara i en sekund istället för denna 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
Relaterat:
- Läs mer om
bc
ochprintf
i mitt svar här: https://stackoverflow.com/questions/12722095/how-do-i-use-floating-point-division-in-bash/58479867#58479867 - Jag kommer inte ihåg var jag först lärde mig om kommandot
time
, men det kan ha varit från @Trudbert svar direkt här .
Svar
Använd endast bash är det också möjligt att mäta och beräkna tidslängden för en del av skalskriptet (eller den förflutna tiden för hela skriptet):
start=$SECONDS ... # do time consuming stuff end=$SECONDS
du kan nu bara skriva ut skillnaden:
echo "duration: $((end-start)) seconds."
om du bara behöver inkrementell varaktighet gör:
echo "duration: $((SECONDS-start)) seconds elapsed.."
Du kan också lagra varaktigheten i en variabel:
let diff=end-start
Kommentarer
- ^ DETTA är svaret folk. Eller enklare: $ SECONDS i slutet. Det ’ är en INBYGGD Bash-variabel. Alla andra svar gör bara extra arbete för att uppfinna detta hjul igen …
- Detta är bara en upprepning av Marks tidigare svar unix.stackexchange .com / a / 340156/155362 .
Svar
Timing-funktion baserad på SECONDS
, begränsad till enbart granularitet på andra nivå, använder inga externa kommandon:
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" }
Till exempel:
time_it sleep 5
ger
2019-03-30_17:24:37 Starting sleep 5 2019-03-30_17:24:42 Finished sleep 5; elapsed = 5 seconds
Svar
Använd bash-tid inbyggd?
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.
Exempel:
TIMEFORMAT="The command took %Rs" time { sleep 0.1 }
Output:
The command took 0.108s
Svar
Här ”är en variant av Alex ”Svar. Jag bryr mig bara om minuter och sekunder, men jag ville också att det skulle formateras annorlunda. Så jag gjorde det här:
start=$(date +%s) end=$(date +%s) runtime=$(python -c "print "%u:%02u" % ((${end} - ${start})/60, (${end} - ${start})%60)")
Kommentarer
- Varför nedröstningen? Har jag ett fel?
- Att använda
python
för den beräkningen ser ut som ett fel för mig heller, sorry man. Varför människor kan ’ inte bara ringatime
är bortom 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 accepterade lösningen använder time
skriver till stderr
.
Lösningen med times
skriver till stdout
.
Lösningarna som använder $SECONDS
saknar precision under sekunden.
De andra lösningarna innefattar att ringa externa program som date
eller perf
vilket inte är effektivt.
Om du mår bra med något av dessa, använd det.
Men om du behöver en effektiv lösning för att få tiden med millisekund precision och behöver dem till variabler så att originalutdata förblir ostörd du kan kombinera processersättning med några omdirigeringar runt time
vilket är mycket snabbare än att ringa externa program och möjliggör omdirigeringar kring timingomslagsskriptet som på det ursprungliga kommandot / 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
Välj en av följande varianter som analyserar utdata från time
som passar dig:
Kortaste variant där stdout
av $Cmd
skrivs till stderr
och inget till stdout
:
read Elapsed User System < <({ time $Cmd 2>&3; } 3>&2 2>&1 >&3)
Längre variant som håller original stdout
och stderr
åtskilda från varandra:
{ read Elapsed User System < <({ time $Cmd 2>&4; } 4>&2 2>&1 >&3); } 3>&1
Den mest komplicerade varianten inkluderar att stänga de extra filbeskrivarna så att $Cmd
kallas som om utan denna timing-omslag runt den och lvm
kommandon som vgs
klagar inte på läckta filbeskrivare:
{ read Elapsed User System < <({ time $Cmd 2>&4 4>&-; } 4>&2 2>&1 >&3 3>&-); } 3>&1
Du kan till och med förfalska ett flytande tillägg i bash
utan att ringa bc
vilket skulle vara mycket långsammare:
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
Möjliga utgångar med de två exemplen på $Cmd
på en långsam 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