Ich möchte die Fertigstellungszeit eines Skripts anzeigen.
Was ich derzeit mache, ist –
#!/bin/bash date ## echo the date at start # the script contents date ## echo the date at end
Dies zeigt nur den Zeitpunkt des Starts und des Endes des Skripts Es ist möglich, eine feinkörnige Ausgabe wie Prozessorzeit / Io-Zeit usw. anzuzeigen.
Kommentare
- stackoverflow.com/questions/385408/ …
- Ich denke, die aktuell akzeptierte Antwort reicht aufgrund zeitlicher Schwankungen nicht wirklich aus.
- @CiroSantilli 事件 事件 2016 六四 事件 法轮功 Ich denke, Ihr vorgeschlagener Thread reicht immer noch nicht aus, um die Auswirkungen zeitlicher Ereignisse zu eliminieren.
- Auch verwandt: stackoverflow.com/questions/5152858/… oder etwas unix.stackexchange.com/questions/334145 / …
- Es gibt einen Befehl, den Sie ausführen können, und dann werden alle Unix-Befehle automatisch mal vergessen / ul>
Antwort
Jus Verwenden Sie time
nicht, wenn Sie das Skript aufrufen:
time yourscript.sh
Kommentare
- Dies wird dreimal ausgegeben:
real
,user
undsys
. Die Bedeutung dieser finden Sie unter hier . - und “ real “ ist wahrscheinlich das, was die Leute wissen wollen – “ Real ist die Wanduhrzeit – Zeit vom Beginn bis zum Ende des Anrufs “
- Gibt es eine Möglichkeit, das Standardout in einer Datei zu erfassen? Beispiel:
time $( ... ) >> out.txt
- Sie können dies auch für Befehlssequenzen in der Befehlszeile tun, z. B.:
time (command1 && command2)
- Oder er könnte in seinem Skript einfach Folgendes tun: $ SECONDS wiedergeben, vorausgesetzt, es ist Bash ….
Antwort
Wenn time
keine Option ist,
start=`date +%s` stuff end=`date +%s` runtime=$((end-start))
Kommentare
- Beachten Sie, dass dies nur funktioniert, wenn Sie ‚ keine Genauigkeit von weniger als einer Sekunde benötigen. Für einige Anwendungen ist dies möglicherweise akzeptabel Für andere nicht. Für eine etwas bessere Genauigkeit (Sie ‚ rufen
date
beispielsweise zweimal auf, also möglicherweise bei Versuchen Sie am besten,date +%s.%N
zu verwenden (%N
ist Nanosekunden seit der gesamten Sekunde) .) - @ChrisH Oh. Gut darauf hinzuweisen; Bash-Arithmetik-Erweiterung ist nur eine ganze Zahl. Ich sehe zwei obvi Optionen; Lassen Sie entweder den Punkt in der Zeichenfolge im Datumsformat fallen (und behandeln Sie den resultierenden Wert als Nanosekunden seit der Epoche), verwenden Sie also
date +%s%N
oder verwenden Sie etwas Stärkeres wiebc
, um die tatsächliche Laufzeit aus den beiden Werten zu berechnen, wie von jwchew vorgeschlagen. Dennoch halte ich diesen Ansatz für eine suboptimale Methode.time
ist aus den oben genannten Gründen erheblich besser, wenn verfügbar. - Installieren Sie einfach
bc
und führen Sie folgende Schritte aus:runtime=$( echo "$end - $start" | bc -l )
- Wenn Ihr Skript mehrere Minuten dauert, verwenden Sie:
echo "Duration: $((($(date +%s)-$start)/60)) minutes
- Weiter zu @ rubo77 Kommentar: Wenn Ihr Skript mehrere Stunden dauert, verwenden Sie
hours=$((runtime / 3600)); minutes=$(( (runtime % 3600) / 60 )); seconds=$(( (runtime % 3600) % 60 )); echo "Runtime: $hours:$minutes:$seconds (hh:mm:ss)"
Antwort
Rufen Sie beim Beenden Ihres Skripts einfach times
ohne Argumente auf.
Mit ksh
oder zsh
, Sie können stattdessen auch time
verwenden. Mit zsh
gibt time
neben user und auch die Wanduhrzeit an System CPU-Zeit.
Um den Exit-Status Ihres Skripts beizubehalten, können Sie Folgendes festlegen:
ret=$?; times; exit "$ret"
Oder Sie kann auch eine Falle für EXIT
hinzufügen:
trap times EXIT
Auf diese Weise werden Zeiten aufgerufen, wenn die Shell beendet wird und Der Exit-Status bleibt erhalten.
$ 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
Beachten Sie auch, dass alle bash
, ksh
und zsh
haben eine spezielle Variable $SECONDS
, die automatisch jede Sekunde erhöht wird. Sowohl in zsh
als auch in ksh93
kann diese Variable auch als Gleitkomma festgelegt werden (mit typeset -F SECONDS
) um mehr Präzision zu bekommen. Dies ist nur die Wanduhrzeit, nicht die CPU-Zeit.
Kommentare
- Diese Variable $ SECONDS ist sehr nützlich, danke!
- Beseitigt Ihr Ansatz die Auswirkung zeitlicher Ereignisse? – – Ich denke, Ihr Ansatz ist in der Nähe des zuvor vorgestellten Ansatzes
time
.- – Ich denke, der im MATLAB-Code vorgestellte Ansatztimeit
kann hier nützlich sein. - Hallo, @St é Phane Chazelas. Ich habe festgestellt, dass
times
‚ keine Wandzeit angibt, oder? Beispiel:bash -c 'trap times EXIT;sleep 2'
- @Binarus, ja, diese Funktion stammt von ksh. Im Gegensatz zu ksh93 / zsh ist neben bash, das kein Gleitkomma unterstützt, ‚ auch ein Fehler aufgetreten, nachdem Sie SECONDS auf 0 gesetzt haben, wird es von 0 auf 1 Sekunde später auf 1 geändert ( da nur das Ergebnis von
time()
berücksichtigt wird, das nur die volle zweite Granularität aufweist). - @Binarus, nicht das ‚ s zwischen 0 und 1. Wenn Sie SECONDS um 12: 00: 00.000 auf 0 setzen, wird es eine Sekunde später auf 1 geändert. Wenn Sie es jedoch auf 12: 00: 00.999 einstellen, wird es eine Millisekunde später auf 1 geändert. Aber ja, ich bin damit einverstanden, dass ‚ in der Praxis wahrscheinlich nicht viel ausmacht, wenn Sie ‚ ohnehin keine Genauigkeit von weniger als einer Sekunde haben.
Antwort
Ich bin etwas spät dran, wollte aber meine Lösung veröffentlichen (aus Gründen der Genauigkeit von weniger als einer Sekunde) ) für den Fall, dass andere beim Suchen auf diesen Thread stoßen. Die Ausgabe erfolgt im Format von Tagen, Stunden, Minuten und schließlich Sekunden:
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
Hoffe auf jemanden da draußen findet das nützlich!
Kommentare
- Ich denke, es gibt keinen anderen (nur bash) Weg als die Verwendung von ‚ bc ‚, um die Berechnungen durchzuführen. Übrigens wirklich gutes Skript;)
- Beachten Sie, dass FreeBSD ‚ s
date
unterstützt keine Genauigkeit von weniger als einer Sekunde und hängt nur das Literal „N
“ an den Zeitstempel an. - Sehr schönes Skript, aber meine Bash funktioniert nicht ‚ behandelt den Teil der zweiten Sekunde nicht. Ich habe auch gelernt, dass / 1 in bc das effektiv entfernt, also habe ich @ / 1 @ zur $ ds-Berechnung hinzugefügt und es zeigt jetzt sehr schöne Dinge an!
- bc unterstützt modulo:
dt2=$(echo "$dt%86400" | bc)
. Ich sage nur … Übrigens, ich bevorzuge die Formdt2=$(bc <<< "${dt}%86400")
, aber diese ‚ ist ganz persönlich. - Ich ‚ Ich weiß noch nichts über
bc
, aber die Division durch86400
macht mich misstrauisch gegenüber dem folgender Grund: Es gibt Tage ohne 86400 Sekunden, z. B. Tage, an denen die Zeit von der Sommerzeit auf die normale Zeit und umgekehrt umgeschaltet wird, oder Tage mit Schaltsekunden. Wenn solche Tage Teil der Zeitspanne sind, die Sie berechnen möchten, dh zwischenres1
undres2
(einschließlich dieser Werte), Ihrem Skript wird wahrscheinlich fehlschlagen.
Antwort
Meine Methode für bash
:
# Reset BASH time counter SECONDS=0 # # do stuff # ELAPSED="Elapsed: $(($SECONDS / 3600))hrs $((($SECONDS / 60) % 60))min $(($SECONDS % 60))sec"
Kommentare
- Dies zeigt die verstrichene Zeit an, aber nicht ‚ “ feinkörnige Ausgabe wie Prozessorzeit, E / A-Zeit “ wie in der Frage angefordert.
- Diejenigen, die nach einer Antwort auf die gestellte Frage suchen, werden diese Lösung wahrscheinlich nützlich finden. Ihr Kommentar ist besser auf die Frage des OP gerichtet.
Antwort
Persönlich möchte ich alle meine Fragen einpacken Skriptcode in einer „Haupt“ -Funktion wie der folgenden:
main () { echo running ... } # stuff ... # calling the function at the very end of the script time main
Beachten Sie, wie einfach die Verwendung des Befehls time
ist In diesem Szenario. Offensichtlich messen Sie nicht die genaue Zeit einschließlich der Skript-Analysezeit, aber ich finde sie in den meisten Situationen genau genug.
Kommentare
- Großartige Lösung, ‚ erfordert keine zusätzlichen Tools und ist in sich geschlossen.
Antwort
#!/bin/bash start=$(date +%s.%N) # HERE BE CODE end=$(date +%s.%N) runtime=$(python -c "print(${end} - ${start})") echo "Runtime was $runtime"
Ja, dies ruft Python auf, aber wenn Sie damit leben können, ist dies eine nette, knappe Lösung.
Kommentare
- Beachten Sie, dass das Ausführen des Befehls
python
in einer Subshell und das Lesen der Ausgabe auf den meisten aktuellen Systemen mehrere Millionen Nanosekunden dauert. Gleiches gilt für das Ausführen vondate
. - “ Mehrere Millionen Nanosekunden “ sind mehrere Millisekunden Leute, die Bash-Skripte zeitlich festlegen, sind normalerweise nicht sehr besorgt darüber (es sei denn, sie führen mehrere Milliarden Skripte pro Megasekunde aus).
- Beachten Sie auch, dass, selbst wenn die Die Berechnung erfolgt innerhalb eines Python-Prozesses. Die Werte wurden vollständig erfasst, bevor Python aufgerufen wurde. Die Ausführungszeit des Skripts wird korrekt gemessen, ohne dass der “ Millionen von Nanosekunden “ Overhead.
-
time main
oben ist so viel sauberer …Ja, wir können mit viel Verschlechterung leben, aber es ist ‚ viel besser, ohne dass ‚ Ingenieure bleiben! -
$(echo $end - $start | bc)
macht dasselbe ohne Python
Antwort
Diese Frage ist ziemlich alt, aber als ich versuchte, meine Lieblingsmethode zu finden, kam dieser Thread hoch … und ich bin überrascht, dass niemand sie erwähnt hat:
perf stat -r 10 -B sleep 1
„perf“ ist ein Tool zur Leistungsanalyse, das im Kernel unter „tools / perf“ enthalten ist und häufig als separates Paket installiert werden kann („perf“ in CentOS und „linux-tools“ unter Debian / Ubuntu). Das Linux Kernal perf Wiki enthält viel mehr Informationen dazu.
Das Ausführen von „perf stat“ enthält einige Details, einschließlich der durchschnittlichen Ausführungszeit ganz am Ende:
1.002248382 seconds time elapsed ( +- 0.01% )
Kommentare
- Was ist
perf
? - @B Layer – hat meine Antwort bearbeitet t o Geben Sie eine kurze Beschreibung von ‚ perf ‚.
-
perf stat
beschwert sich jetzt über “ Möglicherweise haben Sie keine Berechtigung zum Sammeln von Statistiken. “ es sei denn, Sie führen einige Befehle mit , was es in allen Szenarien nutzlos macht, in denen Sie ‚ Ihre Zielmaschine nicht vollständig besitzen. - Erstaunlich, danke! Viel feinkörnigere Lösung als
time
andere vorschlagen. Insbesondere isttime
nicht auf Messcode-Wettbewerbslösungen anwendbar (da ‚ keine Druckzeit in Millisekunden und weniger benötigt wird). , wohingegen Ihre Lösung dies tut.
Antwort
Eine kleine Shell-Funktion, die zuvor hinzugefügt werden kann Befehle zum Messen ihrer Zeit:
tm() { local start=$(date +%s) $@ local exit_code=$? echo >&2 "took ~$(($(date +%s)-${start})) seconds. exited with ${exit_code}" return $exit_code }
Verwenden Sie sie dann in Ihrem Skript oder in Ihrer Befehlszeile wie folgt:
tm the_original_command with all its parameters
Kommentare
- Es wäre sinnvoll, Millisekunden hinzuzufügen, versucht ilke
s=$(date +%s000)
, nicht sicher Wenn es funktioniert. - @loretoparisi für Millisekunden, können Sie
date +%s%N
versuchen. Siehe serverfault.com/questions/151109/… - Dies ist großartig, außer sicherer Verwenden Sie
"$@"
Antwort
#!/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..."
Kommentare
- Wie unterscheidet sich das wirklich von den anderen bereits gegebenen Antworten, die vorher und nachher
date
verwenden? das Skript und geben Sie den Unterschied zwischen ihnen aus?
Antwort
-
Nur benutze
time [any command]
. Beispiel:time sleep 1
schläft für eine Echtzeit (dh wie von einer Stoppuhr gesteuert) von ~ 1.000 bis ~ 1.020 Sekunden, wie hier gezeigt:$ time sleep 1 real 0m1.011s user 0m0.004s sys 0m0.000s
Was für eine schöne Sache. Sie können einen beliebigen Befehl danach setzen und das Ergebnis wird in einer schönen, für Menschen lesbaren Form ausgegeben. Ich benutze es wirklich gerne für Timing-Builds. Beispiel:
# time your "make" build time make # time your "Bazel" build time bazel build //path/to/some:target
… oder für Git-Operationen, die möglicherweise wirklich sein können lang, damit ich realistische mentale Erwartungen entwickeln kann:
# 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 individuellere Timing-Anforderungen müssen Sie möglicherweise die Ausgabe in bash bearbeiten oder in andere Formen konvertieren Verwenden Sie die interne Variable
$SECONDS
. Hier ist eine Demo, einschließlich der Konvertierung dieser Sekunden in andere Einheiten, z. B. Gleitkomma-Minuten:Beachten Sie, dass
dt_min
von0.01666666666...
(1 Sekunde = so viele Minuten) auf0.017
gerundet wird in diesem Fall, da ich die Funktionprintf
zum Runden verwende. Im folgendensleep 1;
-Teil würden Sie Ihr Skript zum Ausführen und zur Zeit aufrufen, aber ich schlafe stattdessen nur 1 Sekunde, um diese Demo zu erstellen.Befehl:
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"
Ausgabe:
dt_sec = 1; dt_min = 0.017
Verwandte Themen:
- Lesen Sie mehr über
bc
undprintf
in meiner Antwort hier: https://stackoverflow.com/questions/12722095/how-do-i-use-floating-point-division-in-bash/58479867#58479867 - Ich kann mich nicht mehr erinnern, wo ich zum ersten Mal von dem Befehl
time
erfahren habe, aber möglicherweise von @Trudberts Antwort hier .
Antwort
Nur mit bash Es ist auch möglich, die Zeitdauer für einen Teil des Shell-Skripts zu messen und zu berechnen (oder die verstrichene Zeit für das gesamte Skript):
start=$SECONDS ... # do time consuming stuff end=$SECONDS
Sie können jetzt entweder einfach die Differenz drucken:
echo "duration: $((end-start)) seconds."
Wenn Sie nur eine inkrementelle Dauer benötigen, gehen Sie wie folgt vor:
echo "duration: $((SECONDS-start)) seconds elapsed.."
Sie können die Dauer auch in einer Variablen speichern:
let diff=end-start
Kommentare
- ^ DAS ist die Antwort Leute. Oder einfacher: $ SECONDS am Ende. Es ‚ ist eine eingebaute Bash-Variable. Alle anderen Antworten machen nur zusätzliche Arbeit, um dieses Rad neu zu erfinden …
- Dies ist nur eine Wiederholung der früheren Antwort von Marks unix.stackexchange .com / a / 340156/155362 .
Antwort
Timing-Funktion basierend auf SECONDS
, nur auf Granularität der zweiten Ebene beschränkt, verwendet keine externen Befehle:
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" }
Zum Beispiel:
time_it sleep 5
gibt
2019-03-30_17:24:37 Starting sleep 5 2019-03-30_17:24:42 Finished sleep 5; elapsed = 5 seconds
Antwort
Bash-Zeit verwenden?
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.
Beispiel:
TIMEFORMAT="The command took %Rs" time { sleep 0.1 }
Ausgabe:
The command took 0.108s
Antwort
Hier ist eine Variation von Alex „s Antwort. Ich kümmere mich nur um Minuten und Sekunden, aber ich wollte auch, dass es anders formatiert wird. Also habe ich Folgendes getan:
start=$(date +%s) end=$(date +%s) runtime=$(python -c "print "%u:%02u" % ((${end} - ${start})/60, (${end} - ${start})%60)")
Kommentare
- Warum die Abwertung? Habe ich einen Fehler?
- Die Verwendung von
python
für diese Berechnung scheint mir ebenfalls ein Fehler zu sein, sorry man. Warum Leute ‚ nicht einfachtime
anrufen können, ist mir ein Rätsel.
Antwort
#!/bin/bash begin=$(date +"%s") Script termin=$(date +"%s") difftimelps=$(($termin-$begin)) echo "$(($difftimelps / 60)) minutes and $(($difftimelps % 60)) seconds elapsed for Script Execution."
Antwort
Die akzeptierte Lösung Mit time
wird in stderr
geschrieben.
Die Lösung mit times
schreibt in stdout
.
Bei den Lösungen mit $SECONDS
fehlt eine Genauigkeit von weniger als einer Sekunde.
Bei den anderen Lösungen werden externe Programme wie aufgerufen date
oder perf
, was nicht effizient ist.
Wenn Sie mit einer dieser Optionen einverstanden sind, verwenden Sie sie.
Wenn Sie jedoch eine effiziente Lösung benötigen, um die Zeiten abzurufen mit Millisekundengenauigkeit und benötigen sie in Variablen , so dass die Die ursprüngliche Ausgabe bleibt ungestört. Sie können die Prozessersetzung mit einigen Umleitungen um time
kombinieren, was viel schneller als das Aufrufen ist externe Programme und ermöglicht Umleitungen um das Timing-Wrapper-Skript wie im ursprünglichen Befehl / Skript.
# 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
Wählen Sie eine der folgenden Varianten aus, um die Ausgabe von time
passend zu Ihren Anforderungen:
Kürzeste Variante, in der stdout
von $Cmd
in stderr
und nichts zu stdout
:
read Elapsed User System < <({ time $Cmd 2>&3; } 3>&2 2>&1 >&3)
Längere Variante, die beibehalten wird Original stdout
und stderr
voneinander getrennt:
{ read Elapsed User System < <({ time $Cmd 2>&4; } 4>&2 2>&1 >&3); } 3>&1
Die komplizierteste Variante umfasst das Schließen der zusätzlichen Dateideskriptoren, sodass $Cmd
aufgerufen wird, als ob ohne diesen Timing-Wrapper und lvm
Befehle wie vgs
beschweren sich nicht über durchgesickerte Dateideskriptoren:
{ read Elapsed User System < <({ time $Cmd 2>&4 4>&-; } 4>&2 2>&1 >&3 3>&-); } 3>&1
Sie kann sogar eine Gleitkommaaddition in bash
vortäuschen, ohne bc
aufzurufen, was viel langsamer wäre:
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ögliche Ausgaben mit den beiden Beispielen von $Cmd
auf einer langsamen 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
Oder:
stdout stderr CPU 0.008 s, Elapsed 0.109 s