Est-il possible d'afficher un compte à rebours ou un chronomètre dans un terminal?

144

Comment puis-je afficher un compte à rebours en temps réel sur le terminal Linux? Existe-t-il une application existante ou, mieux encore, une seule ligne pour le faire?

tir38
la source

Réponses:

184

Je ne sais pas pourquoi vous avez besoin beep, si tout ce que vous voulez, c'est un chronomètre, vous pouvez le faire:

while true; do echo -ne "`date`\r"; done

Cela vous montrera les secondes qui passent en temps réel et vous pourrez l'arrêter avec Ctrl+ C. Si vous avez besoin d'une plus grande précision, vous pouvez l'utiliser pour vous donner des nanosecondes:

while true; do echo -ne "`date +%H:%M:%S:%N`\r"; done

Enfin, si vous voulez vraiment, "format chronomètre", où tout commence à 0 et commence à grandir, vous pouvez faire quelque chose comme ceci:

date1=`date +%s`; while true; do 
   echo -ne "$(date -u --date @$((`date +%s` - $date1)) +%H:%M:%S)\r";
done

Pour un compte à rebours (ce qui n'est pas ce que votre question initiale vous demandait), vous pouvez le faire (changer les secondes en conséquence):

seconds=20; date1=$((`date +%s` + $seconds)); 
while [ "$date1" -ge `date +%s` ]; do 
  echo -ne "$(date -u --date @$(($date1 - `date +%s` )) +%H:%M:%S)\r"; 
done

Vous pouvez les combiner en commandes simples en utilisant les fonctions bash (ou le shell de votre choix). Dans bash, ajoutez ces lignes à votre ~/.bashrc( sleep 0.1cela fera attendre le système pendant 1 / 10ème de seconde entre chaque exécution pour ne pas spammer votre CPU):

function countdown(){
   date1=$((`date +%s` + $1)); 
   while [ "$date1" -ge `date +%s` ]; do 
     echo -ne "$(date -u --date @$(($date1 - `date +%s`)) +%H:%M:%S)\r";
     sleep 0.1
   done
}
function stopwatch(){
  date1=`date +%s`; 
   while true; do 
    echo -ne "$(date -u --date @$((`date +%s` - $date1)) +%H:%M:%S)\r"; 
    sleep 0.1
   done
}

Vous pouvez ensuite démarrer un compte à rebours d’une minute en exécutant:

countdown 60

Vous pouvez compter deux heures avec:

countdown $((2*60*60))

ou une journée entière en utilisant:

countdown $((24*60*60))

Et démarrez le chronomètre en lançant:

stopwatch

Si vous devez être capable de gérer des jours ainsi que des heures, des minutes et des secondes, vous pouvez faire quelque chose comme ceci:

countdown(){
    date1=$((`date +%s` + $1));
    while [ "$date1" -ge `date +%s` ]; do 
    ## Is this more than 24h away?
    days=$(($(($(( $date1 - $(date +%s))) * 1 ))/86400))
    echo -ne "$days day(s) and $(date -u --date @$(($date1 - `date +%s`)) +%H:%M:%S)\r"; 
    sleep 0.1
    done
}
stopwatch(){
    date1=`date +%s`; 
    while true; do 
    days=$(( $(($(date +%s) - date1)) / 86400 ))
    echo -ne "$days day(s) and $(date -u --date @$((`date +%s` - $date1)) +%H:%M:%S)\r";
    sleep 0.1
    done
}

Notez que la stopwatchfonction n'a pas été testée depuis des jours car je ne voulais pas vraiment attendre 24 heures pour cela. Cela devrait fonctionner, mais s'il vous plaît, laissez-moi savoir si cela ne fonctionne pas.

terdon
la source
9
J'ai ajouté ces fonctions intéressantes à ma .zshrcdroite après avoir lu votre réponse. Aujourd’hui, j’ai utilisé countdownla première fois et j’ai remarqué une utilisation assez élevée du processeur. J'ai ajouté un sleep 0.1(je ne sais pas si un temps de repos d'une fraction de seconde est pris en charge sur tous les systèmes), ce qui l'a beaucoup amélioré. L’inconvénient est bien sûr une précision d’affichage moins précise, mais je peux vivre avec un écart de max. 100ms.
Mpy
@mpy merci d'avoir mentionné cela. J'obtiens environ 3% d'utilisation du processeur lorsque bashje fais cela dans , je peux vivre avec cela (même s'il est plus élevé que prévu et j'ai également ajouté le sommeil à mon propre fichier .bashrc).
Terdon
3
Je viens de trouver cette réponse. J'ai trouvé que mettre le retour chariot au début de l'instruction echo dans la fonction chronomètre était pratique car cela signifiait que tuer le chronomètre ne remplaçait pas l'heure actuelle du chronomètre: echo -ne "\ r $ (date -u --date @ $ (( date +%s- $ date1)) +% H:% M:% S) ";
Mkingston
3
@chishaku: Sous OS X, cela semblait fonctionner pour moi: echo -ne "$(date -ju -f %s $(($date1 - date +% s )) +%H:%M:%S)\r";
user1071847
1
Avec paquet sox Je voudrais ajouter un son agréable à jouer à la fin du compte à rebours: play -q -n synth 2 pluck C5.
Pablo Un
94

Ma manière préférée est:

Début:

time cat

Arrêtez:

ctrl+c

Comme @wjandrea a commenté ci-dessous, une autre version est à exécuter:

time read

et appuyez sur Enterpour arrêter

Alfasin
la source
8
similaire, mais vous pouvez appuyer sur Entrée pour l'arrêter:time read
wjandrea
10
time readéchoue dans zsh, mais time (read)fonctionne.
Sparhawk
Le problème, c’est que vous ne pouvez pas voir l’heure sans l’annuler ou la terminer. Lorsque vous le redémarrez, le chronomètre recommence.
Zelphir Kaltstahl
39

Je cherchais la même chose et j'ai fini par écrire quelque chose de plus élaboré en Python:

Cela vous donnera un compte à rebours simple de 10 secondes:

sudo pip install termdown
termdown 10

Source: https://github.com/trehn/termdown

Trehn
la source
1
@DoktoroReichard: C'est un lien de téléchargement.
harrymc
1
@ Suhaib: Il devrait et fait pour moi. S'il vous plaît soulever un problème sur GitHub avec plus d'informations.
Trehn
1
Je l'aime - c'est tout à fait raison
Wayne Werner
1
Très bien, j'aime l'ASCII
Guillermo
1
C'est vraiment cool! 😄
orschiro
13

J'ai utilisé celui-ci:

countdown()
(
  IFS=:
  set -- $*
  secs=$(( ${1#0} * 3600 + ${2#0} * 60 + ${3#0} ))
  while [ $secs -gt 0 ]
  do
    sleep 1 &
    printf "\r%02d:%02d:%02d" $((secs/3600)) $(( (secs/60)%60)) $((secs%60))
    secs=$(( $secs - 1 ))
    wait
  done
  echo
)

Exemple:

 countdown "00:07:55"

Voici une source .

Adobe
la source
2
Compatible
13
sh-3.2# man leave

régler une minuterie pour 15 minutes

sh-3.2# leave +0015
Alarm set for Thu Nov  3 14:19:31 CDT 2016. (pid 94317)
sh-3.2#

edit: J'avais un tas de liens ouverts, et je pensais que c'était spécifique à osx, désolé pour ça. Laissant ma réponse en suspens pour que les autres personnes soient au courant des congés des BSD.

efk
la source
1
Leave fonctionne également sous Linux, mais vous devez d’abord installer le programme Leave à partir des référentiels par défaut.
Karel
6

Ceci est pour un chronomètre avec centièmes de seconde:

#!/usr/bin/awk -f
function z() {
  getline < "/proc/uptime"
  close("/proc/uptime")
  return $0
}
BEGIN {
  x = z()
  while (1) {
    y = z()
    printf "%02d:%05.2f\r", (y - x) / 60, (y - x) % 60
  }
}

Exemple

Steven Penny
la source
Belle solution exclusivement Linux! J'aime le manque d'appels externes. Notez que mon système Debian a deux valeurs dans / proc / uptime, la seconde se référant probablement à mon temps de disponibilité précédent. Ce script peut être ajusté pour remédier à cela en changeant la ligne 5 enreturn $1
Adam Katz
4

J'ai combiné la réponse du très bon terdon à une fonction qui affiche en même temps le temps écoulé depuis le début et le temps jusqu'à la fin. Il existe également trois variantes, ce qui facilite l'appel (il n'est pas nécessaire de faire des calculs élémentaires), et il est également résumé. Exemple d'utilisation :

{ ~ }  » time_minutes 15
Counting to 15 minutes
Start at 11:55:34     Will finish at 12:10:34
     Since start: 00:00:08     Till end:  00:14:51

Et quelque chose comme minuterie de travail:

{ ~ }  » time_hours 8
Counting to 8 hours
Start at 11:59:35   Will finish at 19:59:35
     Since start: 00:32:41     Till end:  07:27:19

Et si vous avez besoin de temps très spécifique:

{ ~ }  » time_flexible 3:23:00
Counting to 3:23:00 hours
Start at 12:35:11   Will finish at 15:58:11
     Since start: 00:00:14     Till end:  03:22:46

Voici le code à mettre dans votre .bashrc

function time_func()
{
   date2=$((`date +%s` + $1));
   date1=`date +%s`;
   date_finish="$(date --date @$(($date2)) +%T )"

   echo "Start at `date +%T`   Will finish at $date_finish"

    while [ "$date2" -ne `date +%s` ]; do
     echo -ne "     Since start: $(date -u --date @$((`date +%s` - $date1)) +%H:%M:%S)     Till end:  $(date -u --date @$(($date2 - `date +%s`)) +%H:%M:%S)\r";
     sleep 1
    done

    printf "\nTimer finished!\n"
    play_sound ~/finished.wav
}

function time_seconds()
{
  echo "Counting to $1 seconds"
  time_func $1
}

function time_minutes()
{
  echo "Counting to $1 minutes"
  time_func $1*60
}

function time_hours()
{
  echo "Counting to $1 hours"
  time_func $1*60*60
}

function time_flexible()  # accepts flexible input hh:mm:ss
{
    echo "Counting to $1"
    secs=$(time2seconds $1)
    time_func $secs
}

function play_sound()  # adjust to your system
{
    cat $1 > /dev/dsp
}

function time2seconds() # changes hh:mm:ss to seconds, found on some other stack answer
{ 
    a=( ${1//:/ }) 
    echo $((${a[0]}*3600+${a[1]}*60+${a[2]})) 
}

Combinez cela avec un moyen de jouer du son sur un terminal linux ( lire un fichier mp3 ou wav via une ligne de commande Linux ) ou cygwin ( cat /path/foo.wav > /dev/dsp fonctionne pour moi dans babun / win7) et vous obtenez un simple timer flexible avec alarme !

Koshmaar
la source
4

Une autre approche

countdown=60 now=$(date +%s) watch -tpn1 echo '$((now-$(date +%s)+countdown))'

Pour Mac:

countdown=60 now=$(date +%s) watch -tn1 echo '$((now-$(date +%s)+countdown))'
#no p option on mac for watch

Si on veut un signal quand il atteint zéro, on peut par exemple le construire avec une commande renvoyant un état de sortie non nul à zéro et le combiner avec watch -b, ou quelque chose du genre, mais si on veut construire un script plus élaboré, c'est probablement pas le chemin à parcourir; il s’agit plus d’une solution de type "one-liner" rapide et sale.


J'aime le watchprogramme en général. Je l'ai vu pour la première fois après avoir déjà écrit d'innombrables while sleep 5; doboucles d'effets différents. watchétait manifestement plus agréable.

Daniel Andersson
la source
3

J'ai fini par écrire mon propre script shell: github gist

#!/bin/sh
# script to create timer in terminal
# Jason Atwood
# 2013/6/22

# start up
echo "starting timer script ..."
sleep 1 # seconds

# get input from user
read -p "Timer for how many minutes?" -e DURATION
DURATION=$(( $DURATION*60 )) # convert minutes to seconds

# get start time
START=$(date +%s)

# infinite loop
while [ -1 ]; do
clear # clear window

# do math
NOW=$(date +%s) # get time now in seconds
DIF=$(( $NOW-$START ))  # compute diff in seconds
ELAPSE=$(( $DURATION-$DIF ))    # compute elapsed time in seconds
MINS=$(( $ELAPSE/60 ))  # convert to minutes... (dumps remainder from division)
SECS=$(( $ELAPSE - ($MINS*60) )) # ... and seconds

# conditional
if [ $MINS == 0 ] && [ $SECS == 0 ] # if mins = 0 and secs = 0 (i.e. if time expired)
then # blink screen
for i in `seq 1 180`; # for i = 1:180 (i.e. 180 seconds)
do
clear # flash on
setterm -term linux -back red -fore white # use setterm to change background color
echo "00:00 " # extra tabs for visibiltiy

sleep 0.5

clear # flash off
setterm -term linux -default # clear setterm changes from above
echo "00:00" # (i.e. go back to white text on black background)
sleep 0.5
done # end for loop
break   # end script

else # else, time is not expired
echo "$MINS:$SECS"  # display time
sleep 1 # sleep 1 second
fi  # end if
done    # end while loop 
tir38
la source
1
Beau scénario, +1. Juste pour que vous sachiez, c'est un compte à rebours, pas un chronomètre.
Terdon
ha tu as raison, c'est ce que je voulais vraiment. Je vais mettre à jour mon nom.
tir38
3

Je suis surpris que personne n'ait utilisé l' sleepenhoutil dans leurs scripts. Au lieu de cela, les solutions proposées utilisent soit un sleep 1entre les sorties de temporisation suivantes, soit une boucle occupée produisant le plus rapidement possible. La première solution est inadéquate car, en raison du peu de temps passé à l’impression, la sortie ne se produira pas une fois par seconde, mais un peu moins que ce qui est sous-optimal. Une fois le temps écoulé, le compteur passera une seconde. Ce dernier est inadéquat car il maintient le processeur occupé sans raison valable.

L'outil que j'ai dans mes $PATHlooks ressemble à ceci:

#!/bin/sh
if [ $# -eq 0 ]; then
    TIMESTAMP=$(sleepenh 0)
    before=$(date +%s)
    while true; do
        diff=$(($(date +%s) - before))
        printf "%02d:%02d:%02d\r" $((diff/3600)) $(((diff%3600)/60)) $((diff%60))
        TIMESTAMP=$(sleepenh $TIMESTAMP 1.0);
    done
    exit 1 # this should never be reached
fi
echo "counting up to $@"
"$0" &
counterpid=$!
trap "exit" INT TERM
trap "kill 0" EXIT
sleep "$@"
kill $counterpid

Le script peut être utilisé comme chronomètre (en comptant jusqu'à l'interruption) ou comme une minuterie qui s'exécute pendant la durée spécifiée. Puisque la sleepcommande est utilisée, ce script permet de spécifier la durée à compter avec la même précision que votre sleeppermet. Sur Debian et ses dérivés, cela inclut des temps de sommeil inférieurs à une seconde et un moyen lisible pour l’heure de spécifier l’heure. Ainsi, par exemple, vous pouvez dire:

$ time countdown 2m 4.6s
countdown 2m 4.6s  0.00s user 0.00s system 0% cpu 2:04.60 total

Et comme vous pouvez le constater, la commande a fonctionné exactement pendant 2 minutes et 4,6 secondes sans trop de magie dans le script lui-même.

EDIT :

L'outil sleepenh provient du paquet du même nom dans Debian et de ses dérivés, comme Ubuntu. Pour les distributions qui ne l'ont pas, cela provient de https://github.com/nsc-deb/sleepenh

L'avantage de sleepenh est qu'il est capable de prendre en compte le petit retard accumulé dans le temps par le traitement de choses autres que le sommeil pendant une boucle. Même si on ne faisait que sleep 110 fois une boucle, l'exécution globale prendrait un peu plus de 10 secondes à cause du petit temps système généré par l'exécution sleepet l'itération de la boucle. Cette erreur s'accumule lentement et rendrait, avec le temps, notre chronomètre de plus en plus imprécis. Pour résoudre ce problème, il est nécessaire que chaque itération de boucle calcule le temps de veille précis, qui est généralement légèrement inférieur à une seconde (pour les temporisateurs d’une seconde). L'outil sleepenh le fait pour vous.

Josch
la source
Je ne comprends pas quel avantage cela donne à ma réponse qui utilise également sleep 0.1. Qu'est-ce que c'est sleepnh(je ne le trouve pas dans les dépôts Arch) et en quoi diffère-t-il sleep? Autant que je sache, vous faites essentiellement la même chose que ma réponse ci-dessus. Qu'est-ce que je rate?
Terdon
@terdon Sleepenh vient d'ici github.com/nsc-deb/sleepenh Le problème avec juste dire sleep 5, c'est que vous ne dormez pas pendant exactement 5 secondes. Essayez par exemple time sleep 5et vous verrez que l'exécution de la commande prend un peu plus de 5 secondes. Au fil du temps, les erreurs s'accumulent. L'utilitaire sleepenh permet d'éviter facilement cette accumulation d'erreur.
josch
D'ACCORD. Sur mon système, je vois une erreur de 0,002 seconde. Je doute vraiment quelqu'un utiliserait ce genre d'outil et attendre mieux que la précision de la milliseconde, mais ce serait mieux si vous modifiez au moins votre réponse et i) expliquer pourquoi sleepnhest meilleure que sleep(vous ne dites d' autres réponses utilisent sleep 1-qui ils ne le font pas , seul le PO l'utilise) et ii) où l'obtenir et comment l'installer car ce n'est pas un outil standard.
Terdon
1
@terdon j'ai expliqué la différence entre sleepet sleepenhdans le premier paragraphe. En tout cas, je n’étais probablement pas assez clair là-dessus, j’ai donc développé davantage à la fin. Les problèmes de précision en millisecondes sont ce que vous obtenez lorsque vous appelez sleepune fois. Ils s'accumulent avec le temps et à un moment donné, c'est perceptible. Je n'ai pas dit que d'autres utilisent seulement sleep 1. J'ai dit qu'ils utilisent sleep 1ou un busyloop. Ce qu'ils font encore. Montrez-moi un contre exemple. Les réponses sleep 0.1sont les mêmes que celles faites, sleep 1sauf qu'elles accumulent les erreurs encore plus rapidement.
josch
Je suis descendu dans les réponses à la recherche de quelqu'un reconnaissant au moins l'existence du problème que vous avez résolu.
mariotomo
2

Réponse courte:

for i in `seq 60 -1 1` ; do echo -ne "\r$i " ; sleep 1 ; done

Explication:

Je sais qu'il y a beaucoup de réponses, mais je veux juste poster quelque chose de très proche de la question de OP, que personnellement, j'accepterais comme " compte à rebours oneliner dans le terminal ". Mes objectifs étaient:

  1. Bon mot.
  2. Compte à rebours.
  3. Facile à mémoriser et à taper dans la console (pas de fonctions ni de logique lourde, uniquement en bash).
  4. Ne nécessite pas de logiciel supplémentaire à installer (peut être utilisé sur n’importe quel serveur que je passe via ssh, même si je n’ai pas la racine là-bas).

Comment ça fonctionne:

  1. seq imprime les nombres de 60 à 1.
  2. echo -ne "\r$i "renvoie le curseur au début de la chaîne et affiche la $ivaleur actuelle . Espace après qu'il soit nécessaire d'écraser la valeur précédente, si elle était plus longue de caractères que la valeur actuelle $i(10 -> 9).
cronfier
la source
1
Cela fonctionnait mieux pour mon cas d'utilisation sur Mac OS pour une utilisation dans un script bash. L'explication de la façon dont cela fonctionne est très utile.
James Campbell
1

Pour référence ultérieure, il existe un outil de ligne de commande appelé µTimer avec des options de ligne de commande très simples pour un minuteur de compte à rebours / à rebours.

À M
la source
1

Imaginez que vous êtes une personne sur OSX à la recherche d'un chronomètre en ligne de commande. Imaginez que vous ne voulez pas installer les outils gnu et que vous voulez simplement utiliser unixdate

dans ce cas, faites comme @terdon mais avec cette modification:

function stopwatch(){
    date1=`date +%s`; 
    while true; do 
        echo -ne "$(date -jf "%s" $((`date +%s` - $date1)) +%H:%M:%S)\r"; 
        sleep 0.1
    done
}
joem
la source
1
Je l'ai essayé sur OS X El Capitan, pour une raison quelconque, il commence à 16:00:00
nopole
1

Utilisez simplement watch + date en heure UTC. Vous pouvez également installer un paquet pour un grand affichage ...

export now="`date +%s -u`";
watch -n 0,1 'date +%T -u -d @$((`date +%s` - $now ))'

#Big plain characters
watch -n 0,1 'date +%T -u -d @$((`date +%s` - $now )) | toilet -f mono12'

#Big empty charaters
watch -n 0,1 'date +%T -u -d @$((`date +%s` - $now )) | figlet -c -f big'

Essayez le!

Voir aussi http://www.cyberciti.biz/faq/create-large-colorful-text-banner-on-screen/

MUY Belgique
la source
1

sw est un simple chronomètre qui fonctionnera pour toujours.

sw

Installer

wget -q -O - http://git.io/sinister | sh -s -- -u https://raw.githubusercontent.com/coryfklein/sw/master/sw

Usage

sw
 - start a stopwatch from 0, save start time in ~/.sw
sw [-r|--resume]
 - start a stopwatch from the last saved start time (or current time if no last saved start time exists)
 - "-r" stands for --resume
Cory Klein
la source
1

Un exemple en python:

#!/usr/bin/python

def stopwatch ( atom = .01 ):
    import time, sys, math

    start = time.time()
    last = start
    sleep = atom/2
    fmt = "\r%%.%sfs" % (int(abs(round(math.log(atom,10))))  if atom<1 else "")
    while True:
        curr = time.time()
        subatom = (curr-last)
        if subatom>atom:
            # sys.stdout.write( "\r%.2fs" % (curr-start))
            sys.stdout.write( fmt % (curr-start))
            sys.stdout.flush()
            last = curr
        else:
            time.sleep(atom-subatom)

stopwatch()

démo

utilisateur84207
la source
1

Jetez un coup d’œil à TermTime , c’est une belle horloge et un chronomètre basés sur un terminal:

pip install termtime

vimiste
la source
0

Ceci est similaire à la réponse acceptée, mais terdon countdown()m'a donné des erreurs de syntaxe. Celui-ci fonctionne bien pour moi, cependant:

function timer() { case "$1" in -s) shift;; *) set $(($1 * 60));; esac; local S=" "; for i in $(seq "$1" -1 1); do echo -ne "$S\r $i\r"; sleep 1; done; echo -e "$S\rTime's up!"; }

Vous pouvez le mettre dans .bashrcpuis exécuter avec: timer t(où t est le temps en minutes).

Andy Forceno
la source
0

Vous avez trouvé cette question plus tôt dans la journée lorsque vous recherchez une application à terme pour afficher un compte à rebours volumineux pour un atelier. Aucune des suggestions ne correspondait exactement à ce dont j'avais besoin, aussi en ai-je rapidement créé une autre dans Go: https://github.com/bnaucler/cdown

Comme la question a déjà reçu une réponse suffisante, considérez cela comme une question de postérité.

B Nauclér
la source
0

Une version graphique du chronomètre

date1=`date +%s`
date1_f=`date +%H:%M:%S____%d/%m`
(
  while true; do 
    date2=$(date -u --date @$((`date +%s` - $date1)) +%H:%M:%S)
    echo "# started at $date1_f \n$date2"
  done
) |
zenity --progress \
  --title="Stop Watch" \
  --text="Stop Watch..." \
  --percentage=0
Mohamed Samy
la source
-2

Si vous souhaitez un programme compilable pour quelque raison que ce soit, voici ce qui convient:

#include <iostream>
#include <string>
#include <chrono>

int timer(seconds count) {
  auto t1 = high_resolution_clock::now();
  auto t2 = t1+count;
  while ( t2 > high_resolution_clock::now()) {
    std::cout << "Seconds Left:" <<
    std::endl <<
      duration_cast<duration<double>>(count-(high_resolution_clock::now()-t1)).count() << 
    std::endl << "\033[2A\033[K";
    std::this_thread::sleep_for(milliseconds(100));
  }
  std::cout << "Finished" << std::endl;
  return 0;
}

Cela peut également être utilisé dans d'autres programmes et facilement porté si un environnement bash n'est pas disponible ou si vous préférez simplement utiliser un programme compilé.

github

aîné4222
la source