Holen Sie sich die Programmausführungszeit in der Shell

407

Ich möchte etwas in einer Linux-Shell unter verschiedenen Bedingungen ausführen und die Ausführungszeit jeder Ausführung ausgeben können.

Ich weiß, dass ich ein Perl- oder Python-Skript schreiben könnte, das dies tun würde, aber gibt es eine Möglichkeit, dies in der Shell zu tun? (was zufällig Bash ist)

ʞɔıu
quelle
2
Windows-Fall: stackoverflow.com/questions/673523/…
n611x007
ist es möglich, so etwas Tickswie den Windows-Fall zu bekommen ?
freeforall tousez
unix.stackexchange.com/questions/52313/…
Ciro Santilli 法轮功 冠状 病 六四 事件 17

Antworten:

534

Verwenden Sie das integrierte timeSchlüsselwort:

$ Hilfezeit

Zeit: Zeit [-p] PIPELINE
    Führen Sie PIPELINE aus und drucken Sie eine Zusammenfassung der Echtzeit, der Benutzer-CPU-Zeit,
    und System-CPU-Zeit, die für die Ausführung von PIPELINE beim Beenden aufgewendet wurde.
    Der Rückgabestatus ist der Rückgabestatus von PIPELINE. Die Option -p
    druckt die Timing-Zusammenfassung in einem etwas anderen Format. Dies verwendet
    Der Wert der Variablen TIMEFORMAT als Ausgabeformat.

Beispiel:

$ time sleep 2
echte 0m2.009s
Benutzer 0m0.000s
sys 0m0.004s
Robert Gamble
quelle
1
Wie wird dies bei einem Befehl verwendet time -p i=x; while read line; do x=x; done < /path/to/file.txt? Es gibt sofort 0,00 zurück, es sei denn, ich setze nichts vor die while-Schleife. Was gibt es?
Natli
Dies ist eine schlechte "Zeit" -Version, Bash eingebaut. Wo ist der externe Befehl 'Zeit'?
Znik
6
@ Znik, versuchen Sie / usr / bin / Zeit
Mark Rajcok
10
@natli: Während timeeine ganze Pipeline so wie sie ist zeitlich festgelegt werden kann (da es sich um ein Bash- Schlüsselwort handelt ), müssen Sie einen Gruppenbefehl ( { ...; ...; }) verwenden, um mehrere Befehle zeitlich zu steuern:time -p { i=x; while read line; do x=x; done < /path/to/file.txt; }
mklement0
2
Um alle Versionen der Zeit type -a time
anzuzeigen
120

Sie können timemit der Zeit (1) viel detailliertere Informationen erhalten als die eingebaute Bash (die Robert Gamble erwähnt ) . Normalerweise ist das so /usr/bin/time.

Anmerkung des Herausgebers: Um sicherzustellen, dass Sie das externe Dienstprogramm time anstelle des time Schlüsselworts Ihrer Shell aufrufen, rufen Sie es als auf /usr/bin/time.
timeist ein von POSIX vorgeschriebenes Dienstprogramm , aber die einzige Option, die unterstützt werden muss, ist -p.
Bestimmte Plattformen implementieren bestimmte, nicht standardmäßige Erweiterungen: Funktioniert -vmit dem Dienstprogramm von GNUtime , wie unten gezeigt (die Frage ist markiert)); Die BSD / macOS-Implementierung verwendet -l, um ähnliche Ausgaben zu erzeugen - siehe man 1 time.

Beispiel für eine ausführliche Ausgabe:


$ /usr/bin/time -v sleep 1
       Command being timed: "sleep 1"
       User time (seconds): 0.00
       System time (seconds): 0.00
       Percent of CPU this job got: 1%
       Elapsed (wall clock) time (h:mm:ss or m:ss): 0:01.05
       Average shared text size (kbytes): 0
       Average unshared data size (kbytes): 0
       Average stack size (kbytes): 0
       Average total size (kbytes): 0
       Maximum resident set size (kbytes): 0
       Average resident set size (kbytes): 0
       Major (requiring I/O) page faults: 0
       Minor (reclaiming a frame) page faults: 210
       Voluntary context switches: 2
       Involuntary context switches: 1
       Swaps: 0
       File system inputs: 0
       File system outputs: 0
       Socket messages sent: 0
       Socket messages received: 0
       Signals delivered: 0
       Page size (bytes): 4096
       Exit status: 0

grepsedawk
quelle
2
Sie würden nicht zufällig wissen, von welchem ​​Debian-Paket das kommen würde? scheint nicht standardmäßig installiert zu sein
22ıu
1
Ich habe auf Ihren Beitrag verwiesen, Robert. Es sei denn, Sie meinen, der von Ihnen vorgeschlagene Befehl ist nicht die eingebaute Bash?
Grepsedawk
24
Erstaunlicherweise wird es von einem Paket namens "time" installiert.
Paul Tomblin
2
Die Ausgabe von / usr / bin / time sieht aus wie "0.00user 0.00system 0: 02.00elapsed 0% CPU (0avgtext + 0avgdata 0maxresident) k 0inputs + 0outputs (0major + 172minor) pagefaults 0swaps"
Paul Tomblin
4
@ Nick: "sudo apt-get Installationszeit".
Robert Gamble
79
#!/bin/bash
START=$(date +%s)
# do something
# start your script work here
ls -R /etc > /tmp/x
rm -f /tmp/x
# your logic ends here
END=$(date +%s)
DIFF=$(( $END - $START ))
echo "It took $DIFF seconds"
David
quelle
14
Es gibt einen viel einfacheren Weg. Bash berechnet automatisch die Spezialvariable $ SECONDS, dann ist eine Neuberechnung basierend auf dem externen Datumsbefehl nicht erforderlich. Die Variable $ SECONDS behält bei, wie viele Sekunden das Bash-Skript beim Start ausgeführt wird. Diese Variable hat eine spezielle Eigenschaft. Siehe Manpage: D
Znik
Ich habe sowohl das Obige als auch die Methode im Kommentar ausprobiert. Im ersten Fall erhalte ich den Fehler "
Unzulässige
45

Versuchen Sie für eine zeilenweise Delta-Messung gnomon .

Ein Befehlszeilenprogramm, ähnlich wie das ts von moreutils, um der Standardausgabe eines anderen Befehls Zeitstempelinformationen voranzustellen. Nützlich für lang laufende Prozesse, bei denen Sie eine historische Aufzeichnung dessen wünschen, was so lange dauert.

Sie können auch die Optionen --highund / oder verwenden --medium, um einen Längenschwellenwert in Sekunden anzugeben, über dem Gnomon den Zeitstempel rot oder gelb hervorhebt. Und Sie können noch ein paar andere Dinge tun.

Beispiel

Adriano Resende
quelle
3
Toller Tipp, aber um ganz klar zu sein: Dies ist nützlich für zeilenweise Timings, aber der Aufwand für die Verwendung derart feinkörniger Timings trägt erheblich zum Gesamt- Timing bei.
mklement0
2
Super Dienstprogramm .. Vielen Dank für das Teilen
Kishan B
19

Wenn Sie mehr Präzision wünschen, verwenden Sie %Nmit date(und verwenden Sie bcfür das Diff, da $(())nur Ganzzahlen verarbeitet werden).

So geht's:

start=$(date +%s.%N)
# do some stuff here
dur=$(echo "$(date +%s.%N) - $start" | bc)

printf "Execution time: %.6f seconds" $dur

Beispiel:

start=$(date +%s.%N); \
  sleep 0.1s; \
  dur=$(echo "$(date +%s.%N) - $start" | bc); \
  printf "Execution time: %.6f seconds\n" $dur

Ergebnis:

Execution time: 0.104623 seconds
Benoit Duffez
quelle
15

Wenn Sie die Zeiten später zum Berechnen verwenden möchten, erfahren Sie, wie Sie die -fOption zum Ausgeben von /usr/bin/timezeitsparendem Code verwenden. Hier ist ein Code, den ich kürzlich verwendet habe, um die Ausführungszeiten einer ganzen Klasse von Schülerprogrammen abzurufen und zu sortieren:

fmt="run { date = '$(date)', user = '$who', test = '$test', host = '$(hostname)', times = { user = %U, system = %S, elapsed = %e } }"
/usr/bin/time -f "$fmt" -o $timefile command args...

Ich habe später alle $timefileDateien verkettet und die Ausgabe an einen Lua-Interpreter weitergeleitet . Sie können dasselbe mit Python oder Bash oder einer anderen Ihrer bevorzugten Syntax tun. Ich liebe diese Technik.

Norman Ramsey
quelle
Hinweis: Der vollständige Pfad /usr/bin/timeist erforderlich, da which timebei einer einfachen Ausführung timedie Version Ihrer Shell ausgeführt wird, die timekeine Argumente akzeptiert.
Kevin Dice
Ich würde gehen mit env time:-)
Ciro Santilli 法轮功 冠状 病 六四 事件 4
13

Wenn Sie nur eine sekundengenaue Genauigkeit benötigen, können Sie die integrierte $SECONDSVariable verwenden, die die Anzahl der Sekunden zählt, die die Shell ausgeführt wurde.

while true; do
    start=$SECONDS
    some_long_running_command
    duration=$(( SECONDS - start ))
    echo "This run took $duration seconds"
    if some_condition; then break; fi
done
Glenn Jackman
quelle
10

Sie können verwenden timeund subshell () :

time (
  for (( i=1; i<10000; i++ )); do
    echo 1 >/dev/null
  done
)

Oder in derselben Schale {}:

time {
  for (( i=1; i<10000; i++ )); do
    echo 1 >/dev/null
  done
}
Eduardo Cuomo
quelle
Sie haben zwei identische Codefragmente gepostet. Sie müssen beabsichtigt haben, dort etwas anderes zu haben.
Stason
3
@StasBekman ist nicht wahr, zuerst wird (& )(neuer Kontext, Subshell ) und andere mit {& verwendet} (gleiche Shell, gleicher Kontext)
Eduardo Cuomo
Aha! Ich sah die beiden sehr genau an und sah keinen Unterschied. Vielen Dank für die Klarstellung, dass {} vs ().
Stason
2

Der Weg ist

$ > g++ -lpthread perform.c -o per
$ > time ./per

Ausgabe ist >>

real    0m0.014s
user    0m0.010s
sys     0m0.002s
Robel Sharma
quelle
Keine Notwendigkeit zu verwenden -lphtreadoder -oTags. Sie müssen nur den timeBefehl verwenden, den die akzeptierte Antwort besser erklärt.
Dennis
7
Es war ein Beispiel. Das ist meine perform.c hat Threading, also brauche ich -lpthread und für eine einfache Identität ist es -o per.
Robel Sharma
0

Eine möglicherweise einfache Methode (die möglicherweise nicht den unterschiedlichen Benutzeranforderungen entspricht) ist die Verwendung der Shell PROMPT.it ist eine einfache Lösung, die in einigen Fällen hilfreich sein kann. Sie können die Bash-Eingabeaufforderungsfunktion wie im folgenden Beispiel verwenden:

export PS1 = '[\ t \ u @ \ h] \ $' 

Der obige Befehl führt dazu, dass die Shell-Eingabeaufforderung wie folgt geändert wird:

[HH: MM: SS-Benutzername @ Hostname] $ 

Jedes Mal, wenn Sie einen Befehl ausführen (oder die Eingabetaste drücken), um zur Shell-Eingabeaufforderung zurückzukehren, zeigt die Eingabeaufforderung die aktuelle Uhrzeit an.

Hinweise:
1) Beachten Sie, dass diese Zeit berücksichtigt werden muss, wenn Sie einige Zeit gewartet haben, bevor Sie Ihren nächsten Befehl eingeben. Dies bedeutet, dass die in der Shell-Eingabeaufforderung angezeigte Zeit der Zeitstempel ist, zu dem die Shell-Eingabeaufforderung angezeigt wurde, und nicht, wenn Sie den Befehl eingeben. Einige Benutzer drücken die Eingabetaste, um eine neue Eingabeaufforderung mit einem neuen Zeitstempel zu erhalten, bevor sie für den nächsten Befehl bereit sind.
2) Es gibt andere verfügbare Optionen und Modifikatoren, mit denen die Bash-Eingabeaufforderung geändert werden kann. Weitere Informationen finden Sie unter (man bash).

tstorym
quelle
Nicht der Punkt, an dem das Programm ausgeführt wird, sondern die Dauer der Programmausführung.
Geno Chen