Wie kann man effektiv die Ausführungszeit eines Skripts ermitteln?

340

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 Beginns und Endes des Skripts. Wäre es möglich, eine feinkörnige Ausgabe wie Prozessorzeit / Io-Zeit usw. anzuzeigen?

mtk
quelle
Ich denke, die aktuell akzeptierte Antwort ist aufgrund zeitlicher Schwankungen nicht ausreichend.
Léo Léopold Hertz 준영
1
@CiroSantilli Mitglied seit 2016 Ich denke, Ihr vorgeschlagener Thread reicht immer noch nicht aus, um den Effekt von zeitlichen Ereignissen zu beseitigen.
Léo Léopold Hertz 준영
Es gibt einen Befehl, den du ausführen kannst und der dann alle Unix-Befehle automatisch mal vergisst, wie man das aktiviert?
powder366

Antworten:

449

Verwenden timeSie einfach, wenn Sie das Skript aufrufen:

time yourscript.sh
Trudbert
quelle
61
Dies gibt dreimal: real, userund sys. Die Bedeutung dieser finden Sie hier .
Garrett
27
und "real" ist wahrscheinlich das, was die Leute wissen wollen - "Real ist Wanduhrzeit - Zeit vom Anfang bis zum Ende des Anrufs"
Brad Parks
3
Gibt es eine Möglichkeit, die Standardausgabe in einer Datei zu erfassen? Zum Beispiel so etwas wietime $( ... ) >> out.txt
Jon
1
Sie können dies auch für Befehlsfolgen in der Befehlszeile tun, z. B .:time (command1 && command2)
meetar
1
Oder er könnte in seinem Drehbuch einfach Folgendes tun: Echo $ SECONDS vorausgesetzt, es ist bash ....
Crossfit_and_Beer
170

Wenn timekeine Option ist,

start=`date +%s`
stuff
end=`date +%s`

runtime=$((end-start))
Rob Bos
quelle
30
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. Versuchen Sie es mit etwas besserer Genauigkeit (Sie rufen datebeispielsweise immer noch zweimal auf, sodass Sie in der Praxis bestenfalls Millisekundengenauigkeit und wahrscheinlich auch weniger erhalten) date +%s.%N. ( %Nist Nanosekunden seit der ganzen Sekunde.)
ein CVn
Guter Punkt. Ich habe gleich nach dem Verlassen der Tastatur daran gedacht, bin aber nicht zurückgekommen. ^^ Denken Sie auch daran, OP, dass "date" selbst ein paar Millisekunden zur Laufzeit hinzufügt.
Rob Bos
2
@ ChrisH Oh. Gut darauf hinzuweisen; Die arithmetische Bash-Erweiterung ist nur Ganzzahlen. Ich sehe zwei offensichtliche Möglichkeiten; Entweder lassen Sie die Periode im Datumsformat weg (und behandeln Sie den resultierenden Wert als Nanosekunden seit der Epoche). Verwenden Sie diese Option date +%s%N, oder verwenden Sie eine leistungsfähigere bcMethode, um die tatsächliche Laufzeit aus den beiden Werten zu berechnen, wie von jwchew vorgeschlagen. Trotzdem halte ich diesen Ansatz für eine suboptimale Methode. timeist aus den oben genannten Gründen erheblich besser, wenn sie verfügbar ist.
ein
10
Einfach installieren bcund dann wie runtime=$( echo "$end - $start" | bc -l )
folgt
10
Wenn Ihr Skript mehrere Minuten dauert, verwenden Sie:echo "Duration: $((($(date +%s)-$start)/60)) minutes
rubo77
75

Rufen Sie einfach timesbeim Beenden Ihres Skripts ohne Argumente auf.

Mit kshoder zshkönnen Sie auch timestattdessen verwenden. Mit zsh, timegeben Sie neben der Benutzer- und System- CPU-Zeit auch die Uhrzeit der Wanduhr an .

Um den Beendigungsstatus Ihres Skripts beizubehalten, können Sie Folgendes festlegen:

ret=$?; times; exit "$ret"

Oder Sie können auch eine Falle hinzufügen EXIT:

trap times EXIT

Auf diese Weise werden Zeiten aufgerufen, wenn die Shell beendet wird und der Beendigungsstatus beibehalten wird.

$ 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, kshund zshhat eine $SECONDSspezielle Variable , die automatisch jede Sekunde erhöht werden. In beide zshund ksh93kann diese Variable auch Floating - Point vorgenommen werden (mit typeset -F SECONDS) mehr Präzision zu erhalten. Dies ist nur die Wanduhrzeit, nicht die CPU-Zeit.

Stéphane Chazelas
quelle
12
Diese $ SECONDS-Variable ist sehr nützlich, danke!
Andybuckley
Beseitigt Ihr Ansatz die Auswirkung zeitlicher Ereignisse? - - Ich denke, Ihr Ansatz ist in der Nähe des timezuvor vorgestellten Ansatzes. - - Ich denke, der timeitin MATLAB-Code vorgestellte Ansatz kann hier nützlich sein.
Léo Léopold Hertz 준영
2
Hallo, @ Stéphane Chazelas. Ich habe festgestellt, dass timeses keine Wandzeit gibt, oder? Beispiel:bash -c 'trap times EXIT;sleep 2'
user15964
32

Ich bin ein bisschen spät dran am Zug, wollte aber meine Lösung posten (für eine Genauigkeit von weniger als einer Sekunde), falls andere durch die Suche auf diesen Thread stoßen. Die Ausgabe erfolgt im Format Tage, Stunden, Minuten und zuletzt 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)

printf "Total runtime: %d:%02d:%02d:%02.4f\n" $dd $dh $dm $ds

Hoffe, jemand da draußen findet das nützlich!

jwchew
quelle
1
Ich denke, es gibt keinen anderen (nur bash) Weg, als 'bc' für die Berechnungen zu verwenden. Übrigens wirklich gutes Drehbuch;)
TVL
1
Beachten Sie, dass FreeBSDs datekeine Genauigkeit von weniger als einer Sekunde unterstützen und lediglich ein wörtliches " N" an den Zeitstempel anhängen .
Anton Samsonov
1
Sehr nettes Skript, aber meine Bash behandelt den zweiten Teil 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 nette Dinge an!
Daniel
1
bc unterstützt Modulo: dt2=$(echo "$dt%86400" | bc). Ich sage nur ... Übrigens bevorzuge ich die Form, dt2=$(bc <<< "${dt}%86400")aber das ist ganz persönlich.
Dani_l
16

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"
Kennzeichen
quelle
Dies zeigt die verstrichene Zeit, aber nicht die in der Frage angeforderte "feinkörnige Ausgabe wie Prozessorzeit, E / A-Zeit".
Roaima
3
Diejenigen, die nach einer Antwort auf die gestellte Frage suchen, werden diese Lösung wahrscheinlich nützlich finden. Ihr Kommentar wäre besser an die Frage des OP gerichtet.
Mark
5
#!/bin/bash
start=$(date +%s.%N)

# HERE BE CODE

end=$(date +%s.%N)    
runtime=$(python -c "print(${end} - ${start})")

echo "Runtime was $runtime"

Ja, das nennt sich Python, aber wenn Sie damit leben können, dann ist dies eine nette, knappe Lösung.

Alex
quelle
5
pythonBeachten Sie, dass das Ausführen dieses Befehls in einer Subshell und das Lesen seiner Ausgabe auf den meisten aktuellen Systemen mehrere Millionen Nanosekunden dauert. Gleiches gilt fürs Laufen date.
Stéphane Chazelas
7
"Mehrere Millionen Nanosekunden" sind mehrere Millisekunden. Die 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).
Zilk
2
Beachten Sie auch, dass die Werte, selbst wenn die Berechnung innerhalb eines Python-Prozesses erfolgt, vollständig erfasst wurden, bevor Python aufgerufen wurde. Die Ausführungszeit des Skripts wird korrekt gemessen, ohne den Overhead "Millionen von Nanosekunden".
Victor Schröder
5

Diese Frage ist ziemlich alt, aber als ich versuchte, meine Lieblingsmethode zu finden, kam dieser Thread hoch ... und ich bin überrascht, dass niemand darauf eingegangen ist:

perf stat -r 10 -B sleep 1

'perf' ist ein Tool zur Leistungsanalyse, das im Kernel unter 'tools / perf' enthalten ist und oft 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 eine ganze Reihe von Details, einschließlich der durchschnittlichen Ausführungszeit am Ende:

1.002248382 seconds time elapsed                   ( +-  0.01% )
Zaahid
quelle
2
Was ist perf?
B Schicht
@B Layer - bearbeitete meine Antwort, um eine kurze Beschreibung von 'perf' zu geben.
Zaahid
1
perf statbeschwert sich jetzt über "Sie haben möglicherweise nicht die Erlaubnis, Statistiken zu sammeln." es sei denn, Sie führen einige Befehle mit aus sudo, wodurch es in allen Szenarien, in denen Sie den Zielcomputer nicht vollständig besitzen, unbrauchbar wird.
Alamar
4

Eine kleine Shell-Funktion, die vor Befehlen hinzugefügt werden kann, um ihre Zeit zu messen:

tm() {
  s=$(date +%s)
  $@
  rc=$?
  echo "took $[$(date +%s)-$s] seconds. return code $rc" >&2
  return $rc
}

Verwenden Sie es dann in Ihrem Skript oder in Ihrer Befehlszeile wie folgt:

tm the_original_command with all its parameters
Evgeny
quelle
Es wäre wert, Millisekunden hinzuzufügen, versuchte ilke s=$(date +%s000), nicht sicher, ob es funktioniert.
Loretoparisi
3

Hier ist eine Variation von Alex 'Antwort. Ich kümmere mich nur um Minuten und Sekunden, aber ich wollte es auch anders formatieren. Also habe ich das gemacht:

start=$(date +%s)
end=$(date +%s)
runtime=$(python -c "print '%u:%02u' % ((${end} - ${start})/60, (${end} - ${start})%60)")
mpontillo
quelle
1
Warum die Gegenstimme? Habe ich einen Bug?
mpontillo
3
#!/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..."
Shicheng Guo
quelle
7
Inwiefern unterscheidet sich das wirklich von den anderen bereits gegebenen Antworten, die datevor und nach dem Skript verwendet werden und die den Unterschied zwischen ihnen ausgeben?
Eric Renouf
2

Mit nur bash ist es auch möglich, die Zeitdauer für einen Teil des Shell-Skripts (oder die verstrichene Zeit für das gesamte Skript) zu messen und zu berechnen :

start=$SECONDS

... # do time consuming stuff

end=$SECONDS

Sie können jetzt entweder nur den Unterschied 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
gauteh
quelle
^ DAS ist die Antwort Leute. Oder einfacher: $ SECONDS am Ende. Es ist eine BUILT-IN-Bash-Variable. Alle anderen Antworten machen nur zusätzliche Arbeit, um dieses Rad neu zu erfinden ...
Crossfit_and_Beer
2

Persönlich möchte ich meinen gesamten Skriptcode in eine "Haupt" -Funktion einbetten:

main () {
 echo running ...
}

# stuff ...

# calling the function at the very end of the script
time main

Beachten Sie, wie einfach die Verwendung des timeBefehls in diesem Szenario ist. Natürlich messen Sie nicht die genaue Zeit einschließlich der Skriptanalysezeit, aber ich finde sie in den meisten Situationen genau genug.

LeZuse
quelle
1
#!/bin/bash
begin=$(date +"%s")

Script

termin=$(date +"%s")
difftimelps=$(($termin-$begin))
echo "$(($difftimelps / 60)) minutes and $(($difftimelps % 60)) seconds elapsed for Script Execution."
Arun Binoy
quelle
1

Die Timing-Funktion SECONDS, die auf der Second-Level-Granularität basiert , 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
Codeforester
quelle