Obtenir le temps d'exécution du programme dans le shell

407

Je veux exécuter quelque chose dans un shell Linux sous quelques conditions différentes, et être capable de produire le temps d'exécution de chaque exécution.

Je sais que je pourrais écrire un script perl ou python qui ferait cela, mais est-il possible de le faire dans le shell? (qui se trouve être bash)

ʞɔıu
la source
2
Cas Windows: stackoverflow.com/questions/673523/…
n611x007
est-il possible d'obtenir le Ticksmême que le boîtier Windows?
freeforall tousez
unix.stackexchange.com/questions/52313/…
Ciro Santilli 郝海东 冠状 病 六四 事件 法轮功

Réponses:

534

Utilisez le timemot - clé intégré :

$ help time

time: time [-p] PIPELINE
    Exécutez PIPELINE et imprimez un résumé du temps réel, du temps CPU de l'utilisateur,
    et le temps processeur système passé à exécuter PIPELINE à la fin de celui-ci.
    Le statut de retour est le statut de retour de PIPELINE. L'option `-p '
    imprime le résumé de synchronisation dans un format légèrement différent. Cela utilise
    la valeur de la variable TIMEFORMAT comme format de sortie.

Exemple:

$ time sleep 2
réel 0m2.009s
utilisateur 0m0.000s
sys 0m0.004s
Robert Gamble
la source
1
Comment est-ce utilisé sur une commande comme time -p i=x; while read line; do x=x; done < /path/to/file.txt? Il renvoie immédiatement 0,00 sauf si je ne mets rien avant la boucle while .. qu'est-ce qui donne?
natli
c'est une mauvaise version «temps», bash builtin. où est la commande externe «time»?
Znik
6
@Znik, essayez / usr / bin / time
Mark Rajcok
10
@natli: Bien que vous timepuissiez chronométrer un pipeline entier tel quel (en raison d'être un mot-clé Bash ), vous devez utiliser une commande de groupe ( { ...; ...; }) pour chronométrer plusieurs commandes:time -p { i=x; while read line; do x=x; done < /path/to/file.txt; }
mklement0
2
Pour voir toutes les versions de temps que vous avez installées sur votre système, vous pouvez utilisertype -a time
spinup le
120

Vous pouvez obtenir des informations beaucoup plus détaillées que le bash intégré time(que Robert Gamble mentionne) en utilisant time (1) . C'est normalement le cas /usr/bin/time.

Note de l'éditeur: pour vous assurer que vous appelez l' utilitaire externe time plutôt que le time mot clé de votre shell , invoquez-le en tant que /usr/bin/time.
timeest un utilitaire mandaté par POSIX , mais la seule option qu'il doit prendre en charge est -p.
Des plates-formes spécifiques implémentent des extensions spécifiques non standard: -vfonctionne avec l' utilitaire GNUtime , comme illustré ci-dessous (la question est balisée); l'implémentation BSD / macOS utilise -lpour produire une sortie similaire - voir man 1 time.

Exemple de sortie détaillée:


$ /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
la source
2
vous ne sauriez pas de quel paquet debian cela proviendrait? ne semble pas être installé par défaut
ʞɔıu
1
Je faisais référence à votre message, Robert. À moins que vous ne vouliez dire que la commande que vous suggérez n'est pas le bash intégré?
grepsedawk
24
Étonnamment, il est installé à partir d'un package appelé "time".
Paul Tomblin
2
La sortie de / usr / bin / time ressemble à "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 install time".
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
la source
14
Il existe un moyen beaucoup plus simple. Bash calcule automatiquement la variable spéciale $ SECONDS, puis le recalcul basé sur la commande de date externe est inutile. La variable $ SECONDS conserve le nombre de secondes pendant lesquelles le script bash est en cours d'exécution au démarrage. Cette variable a une propriété spéciale. Voir la page de manuel: D
Znik
J'ai essayé à la fois ce qui précède et la méthode dans le commentaire. Dans le 1er, j'obtiens une erreur «variable illégale» et le 2e, je reçois «variable non identifiée»
DrBwts
45

Pour une mesure delta ligne par ligne, essayez gnomon .

Un utilitaire de ligne de commande, un peu comme le ts de moreutils, pour ajouter des informations d'horodatage à la sortie standard d'une autre commande. Utile pour les processus de longue durée où vous souhaitez un historique de ce qui prend si longtemps.

Vous pouvez également utiliser les options --highet / ou --mediumpour spécifier un seuil de longueur en secondes, sur lequel gnomon mettra en surbrillance l'horodatage en rouge ou en jaune. Et vous pouvez aussi faire quelques autres choses.

exemple

Adriano Resende
la source
3
Très bon conseil, mais juste pour être clair: cela est utile pour les timings ligne par ligne , mais le surcoût lié à la prise de tels timbres à grain fin ajoute considérablement au timing global .
mklement0
2
Utilitaire génial .. Merci pour le partage
Kishan B
19

Si vous voulez plus de précision, utilisez %Navec date(et utilisez bcpour le diff, car $(())ne gère que les entiers).

Voici comment procéder:

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

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

Exemple:

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

Résultat:

Execution time: 0.104623 seconds
Benoit Duffez
la source
15

Si vous avez l'intention d'utiliser les heures plus tard pour calculer avec, découvrez comment utiliser l' -foption de /usr/bin/timepour générer du code qui fait gagner du temps. Voici du code que j'ai utilisé récemment pour obtenir et trier les temps d'exécution de toute une classe de programmes d'étudiants:

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...

Plus tard, j'ai concaténé tous les $timefilefichiers et dirigé la sortie vers un interpréteur Lua . Vous pouvez faire de même avec Python ou bash ou quelle que soit votre syntaxe préférée. J'adore cette technique.

Norman Ramsey
la source
Remarque: Le chemin complet /usr/bin/timeest nécessaire car bien which timeque vous dira le contraire, si vous exécutez simplement time, il exécutera la version de votre shell timequi n'accepte aucun argument.
Kevin Dice
env time
J'irais
13

Si vous avez seulement besoin d'une précision à la seconde près, vous pouvez utiliser la $SECONDSvariable intégrée , qui compte le nombre de secondes pendant lesquelles le shell a été exécuté.

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
la source
10

Vous pouvez utiliser timeet sous - shell() :

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

Ou dans la même coque {}:

time {
  for (( i=1; i<10000; i++ )); do
    echo 1 >/dev/null
  done
}
Eduardo Cuomo
la source
Vous avez publié deux extraits de code identiques. Vous devez avoir voulu avoir quelque chose de différent là-bas.
stason
3
@StasBekman n'est pas vrai, utilisant d'abord (& )(nouveau contexte, sous - shell ), et d'autres avec {& }(même shell, même contexte)
Eduardo Cuomo
Ah! Je regardais très fort les deux et je n'ai pas vu la différence. Merci d'avoir précisé que {} vs ().
stason
2

Le chemin est

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

la sortie est >>

real    0m0.014s
user    0m0.010s
sys     0m0.002s
Robel Sharma
la source
Pas besoin d'utiliser -lphtreadou de -obalises. Il suffit d'utiliser la timecommande, ce que la réponse acceptée explique mieux.
Dennis
7
C'était un exemple. C'est mon perform.c a un thread donc j'ai besoin de -lpthread et pour une identité simple c'est -o per.
Robel Sharma
0

une méthode peut-être simple (qui peut ne pas répondre aux besoins des différents utilisateurs) est l'utilisation du shell PROMPT.it est une solution simple qui peut être utile dans certains cas. Vous pouvez utiliser la fonction d'invite bash comme dans l'exemple ci-dessous:

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

La commande ci-dessus entraînera la modification de l'invite du shell en:

[HH: MM: SS nom d'utilisateur @ nom d'hôte] $ 

Chaque fois que vous exécutez une commande (ou appuyez sur Entrée) pour revenir à l'invite du shell, l'invite affiche l'heure actuelle.

notes:
1) sachez que si vous avez attendu un certain temps avant de taper votre prochaine commande, cette heure doit être prise en compte, c'est-à-dire que l'heure affichée dans l'invite du shell est l'horodatage lorsque l'invite du shell a été affichée, pas lorsque vous entrez la commande. certains utilisateurs choisissent d'appuyer sur la touche Entrée pour obtenir une nouvelle invite avec un nouvel horodatage avant d'être prêts pour la prochaine commande.
2) Il existe d'autres options et modificateurs disponibles qui peuvent être utilisés pour modifier l'invite bash, reportez-vous à (man bash) pour plus de détails.

tstorym
la source
Pas le moment où le programme s'exécute, mais la durée de l'exécution du programme.
Geno Chen