306 votes

Comment calculer le temps écoulé dans le bash script ?

J'imprime l'heure de début et de fin en utilisant date +"%T" ce qui donne quelque chose comme :

10:33:56
10:36:10

Comment pourrais-je calculer et imprimer la différence entre les deux ?

J'aimerais obtenir quelque chose comme :

2m 14s

5 votes

Dans un autre ordre d'idées, ne pourriez-vous pas utiliser le time commande ?

1 votes

Utilisez le temps unix à la place, date +%s puis soustraire pour obtenir la différence en secondes.

657voto

Daniel Kamil Kozar Points 5317

Bash a une fonction pratique SECONDS variable intégrée qui indique le nombre de secondes écoulées depuis le démarrage de l'interpréteur de commandes. Cette variable conserve ses propriétés lorsqu'elle est assignée, et la valeur renvoyée après l'assignation est le nombre de secondes écoulées depuis l'assignation plus la valeur assignée.

Ainsi, vous pouvez simplement définir SECONDS à 0 avant de lancer l'événement minuté, il suffit de lire SECONDS après l'événement, et faire l'arithmétique du temps avant de l'afficher.

#!/usr/bin/env bash

SECONDS=0
# do some work
duration=$SECONDS
echo "$(($duration / 60)) minutes and $(($duration % 60)) seconds elapsed."

Comme cette solution ne dépend pas de date +%s (qui est une extension GNU), il est portable sur tous les systèmes supportés par Bash.

69 votes

+1. Par ailleurs, vous pouvez tromper date en effectuant l'arithmétique du temps pour vous, en écrivant date -u -d @"$diff" +'%-Mm %-Ss' . (Cela interprète $diff en tant que secondes depuis l'époque, et calcule les minutes et les secondes en UTC). Mais ce n'est probablement pas plus élégant, juste mieux caché :-P

24 votes

C'est simple et agréable. Si quelqu'un a besoin d'heures : echo "$(($diff / 3600)) hours, $((($diff / 60) % 60)) minutes and $(($diff % 60)) seconds elapsed."

9 votes

Il faut lire $(date -u +%s) pour empêcher une condition de course sur les dates où l'heure d'été est changée. Et attention aux méchantes secondes intercalaires ;)

45voto

Dorian Points 2384

Voici comment j'ai procédé :

START=$(date +%s);
sleep 1; # Your stuff
END=$(date +%s);
echo $((END-START)) | awk '{print int($1/60)":"int($1%60)}'

Très simple, prenez le nombre de secondes au début, puis prenez le nombre de secondes à la fin, et imprimez la différence en minutes:secondes.

7 votes

En quoi est-ce différent de ma solution ? Je ne vois vraiment pas l'intérêt d'appeler awk dans ce cas, puisque Bash gère tout aussi bien l'arithmétique des nombres entiers.

2 votes

Votre réponse est également correcte. Certaines personnes, comme moi, préfèrent travailler avec awk plutôt qu'avec les incohérences de bash.

2 votes

Pourriez-vous nous en dire plus sur les incohérences de Bash concernant l'arithmétique des nombres entiers ? J'aimerais en savoir plus à ce sujet, car je n'en avais pas connaissance.

12voto

Zskdan Points 166

Je voudrais proposer une autre façon d'éviter de rappeler date commande. Cela peut s'avérer utile si vous avez déjà rassemblé des horodatages en %T le format de la date :

ts_get_sec()
{
  read -r h m s <<< $(echo $1 | tr ':' ' ' )
  echo $(((h*60*60)+(m*60)+s))
}

start_ts=10:33:56
stop_ts=10:36:10

START=$(ts_get_sec $start_ts)
STOP=$(ts_get_sec $stop_ts)
DIFF=$((STOP-START))

echo "$((DIFF/60))m $((DIFF%60))s"

on peut même traiter les millisecondes de la même manière.

ts_get_msec()
{
  read -r h m s ms <<< $(echo $1 | tr '.:' ' ' )
  echo $(((h*60*60*1000)+(m*60*1000)+(s*1000)+ms))
}

start_ts=10:33:56.104
stop_ts=10:36:10.102

START=$(ts_get_msec $start_ts)
STOP=$(ts_get_msec $stop_ts)
DIFF=$((STOP-START))

min=$((DIFF/(60*1000)))
sec=$(((DIFF%(60*1000))/1000))
ms=$(((DIFF%(60*1000))%1000))

echo "${min}:${sec}.$ms"

1 votes

Existe-t-il un moyen de traiter les millisecondes, par exemple 10:33:56.104

0 votes

Le traitement des millisecondes se comporte mal si le champ des millisecondes commence par un zéro. Par exemple, ms="033" donnera comme chiffre de fin "027" parce que le champ ms est interprété en octal. en changeant "echo" ... "+ms))" en ... "+${ms##+(0)}))" résoudra ce problème tant que "shopt -s extglob" apparaît quelque part au-dessus dans le script. On devrait probablement enlever les zéros de tête de h, m, et s aussi...

3 votes

echo $(((60*60*$((10#$h)))+(60*$((10#$m)))+$((10#$s)))) a fonctionné pour moi depuis que j'ai value too great for base (error token is "08")

7voto

redolent Points 1269

Voici un peu de magie :

time1=14:30
time2=$( date +%H:%M ) # 16:00
diff=$(  echo "$time2 - $time1"  | sed 's%:%+(1/60)*%g' | bc -l )
echo $diff hours
# outputs 1.5 hours

sed remplace un : avec une formule pour convertir en 1/60. Ensuite, le calcul du temps qui est fait par bc

7voto

rags Points 21

À partir de la date (GNU coreutils) 7.4, vous pouvez maintenant utiliser -d pour faire de l'arithmétique :

$ date -d -30days
Sat Jun 28 13:36:35 UTC 2014

$ date -d tomorrow
Tue Jul 29 13:40:55 UTC 2014

Les unités que vous pouvez utiliser sont les jours, les années, les mois, les heures, les minutes et les secondes :

$ date -d tomorrow+2days-10minutes
Thu Jul 31 13:33:02 UTC 2014

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X