2013-06-24 20:13:51 +0000 2013-06-24 20:13:51 +0000
157
157

Existe uma forma de mostrar um contador decrescente ou um cronómetro num terminal?

Como posso exibir um contador decrescente em tempo real no terminal Linux? Existe alguma aplicação existente ou, melhor ainda, um liner para o fazer?

Respostas (22)

195
195
195
2013-06-24 22:11:13 +0000

Não tenho a certeza porque precisa de beep, se tudo o que quer é um cronómetro, pode fazer isto:

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

Isso mostrar-lhe-á os segundos que passam em tempo real e pode pará-lo com Ctrl+C. Se precisar de maior precisão, pode usar isto para lhe dar nanossegundos:

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

Finalmente, se realmente, quiser “formato de cronómetro”, onde tudo começa em 0 e começa a crescer, pode fazer algo como isto:

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

Para um temporizador de contagem decrescente (que não é o que a sua pergunta original lhe pediu) poderia fazer isto (mudar segundos em conformidade):

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

Pode combiná-los em comandos simples, usando funções bash (ou qualquer concha que prefira). Na bash, adicione estas linhas ao seu ~/.bashrc (o sleep 0.1 fará o sistema esperar 1/10 de segundo entre cada execução para que não faça spam no seu 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
}

Pode então iniciar uma contagem decrescente de um minuto correndo:

countdown 60

Pode contar duas horas com:

countdown $((2*60*60))

ou um dia inteiro de utilização:

countdown $((24*60*60))

E iniciar o cronómetro correndo:

stopwatch

Se precisar de ser capaz de lidar com dias assim como com horas, minutos e segundos, pode fazer algo como isto:

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
}

Nota que a função stopwatch não foi testada durante dias, uma vez que eu não queria realmente esperar 24 horas por ela. Deve funcionar, mas por favor avisem-me se não funcionar.

100
100
100
2015-03-30 08:26:08 +0000

A minha maneira preferida é:

Start:

time cat

Stop:

ctrl+c

Como @wjandrea comentou abaixo, outra versão deve ser executada:

time read

e pressionar Enter para parar

46
46
46
2014-06-06 07:06:57 +0000

Eu procurava a mesma coisa e acabei por escrever algo mais elaborado em Python:

Isto dar-lhe-á uma simples contagem decrescente de 10 segundos:

sudo pip install termdown
termdown 10

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

14
14
14
2016-11-03 19:06:37 +0000
sh-3.2# man leave

definir um temporizador para 15 minutos

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

editar: eu tinha um monte de links abertos, e pensei que isto era específico para osx, lamento por isso. Deixando a minha resposta para que outros estejam cientes da licença nos BSDs.

13
13
13
2013-06-26 19:52:03 +0000

Já usei este aqui:

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
)

Exemplo:

countdown "00:07:55"

Aqui está uma fonte .

6
6
6
2013-12-29 05:42:56 +0000

Isto é para um cronómetro com centésimos de segundo:

#!/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
  }
}

Exemplo

5
5
5
2019-06-05 10:48:15 +0000

Resposta curta:

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

Explicação:

Sei que há muitas respostas, mas quero apenas colocar algo muito próximo da pergunta da OP, que pessoalmente aceitaria como de facto “ contagem regressiva de um terminal”. Os meus objectivos eram:

  1. um liner.
  2. Contagem decrescente.
  3. Fácil de lembrar e digitar na consola (sem funções e lógica pesada, apenas bash).
  4. Não requer instalação de software adicional (pode ser utilizado em qualquer servidor que eu vá via ssh, mesmo que eu não tenha lá raiz).

Como funciona:

  1. seq imprime números de 60 a 1.
  2. echo -ne "\r$i " devolve o carpete ao início da corda e imprime o valor actual $i. Espaço depois é necessário para sobrescrever o valor anterior, se foi mais longo por caracteres do que o actual $i (10 -> 9).
4
4
4
2015-02-01 14:42:54 +0000

Combinei a muito boa resposta do terdon, em função que ao mesmo tempo mostra o tempo desde o início, e o tempo até ao fim. Existem também três variantes, por isso é mais fácil de chamar (não é preciso fazer contas de bash), e também é abstraído. Exemplo de utilização :

{ ~ } » 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

E algo parecido com o tempo de trabalho:

{ ~ } » 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

E se precisar de algum tempo muito específico:

{ ~ } » 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

Aqui está o código* a colocar no seu . 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]})) 
}

Combine isto com alguma forma de disponibilizar som* no terminal linux play mp3 ou ficheiro wav via linha de comando Linux ) ou cygwin (cat /path/foo.wav > /dev/dsp funciona para mim em babun/win7) e tem um simples temporizador flexível com alarme*!

3
3
3
2013-06-25 00:40:38 +0000

Acabei por escrever o meu próprio guião de concha: 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
3
3
3
2016-11-24 15:38:57 +0000

Surpreende-me que ninguém tenha utilizado a ferramenta sleepenh nos seus guiões. Em vez disso, as soluções propostas ou utilizam um sleep 1 entre saídas temporizadas subsequentes ou um loop ocupado que sai o mais rápido possível. A primeira é inadequada porque, devido ao pouco tempo gasto na impressão, a saída não irá realmente acontecer uma vez por segundo, mas um pouco menos do que a que é subóptima. Depois de passado tempo suficiente, o contador saltará um segundo. O último é inadequado porque mantém o CPU ocupado sem qualquer razão válida.

A ferramenta que tenho no meu $PATH parece-se com isto:

#!/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

O script pode ser usado como um relógio de paragem (contagem até ser interrompido) ou como um temporizador que funciona durante o período de tempo especificado. Uma vez que o comando sleep é utilizado, este script permite especificar a duração para a qual contar com a mesma precisão que o seu sleep permite. Em Debian e derivados, isto inclui o sub-segundo segundo que dorme e uma forma agradável e legível para o ser humano de especificar o tempo. Assim, por exemplo, pode dizer:

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

E como pode ver, o comando funcionou exactamente durante 2 minutos e 4,6 segundos sem muita magia no próprio guião.

EDIT :

A ferramenta sleepenh vem do pacote com o mesmo nome em Debian e os seus derivados como o Ubuntu. Para distribuições que não o têm, vem de https://github.com/nsc-deb/sleepenh

A vantagem do sleepenh é, que é capaz de ter em conta o pequeno atraso que se acumula ao longo do tempo a partir do processamento de outras coisas que não o sono durante um loop. Mesmo que se fizesse apenas sleep 1 num loop 10 vezes, a execução global levaria um pouco mais de 10 segundos devido à pequena sobrecarga que advém da execução de sleep e da iteração do loop. Este erro acumula-se lentamente e, com o tempo, tornaria o nosso cronómetro cada vez mais impreciso. Para resolver este problema, cada iteração de laço deve calcular o tempo preciso para dormir, que normalmente é ligeiramente inferior a um segundo (para temporizadores de intervalo de um segundo). A ferramenta sleepenh faz isto por si.

3
3
3
2014-08-21 19:13:05 +0000

Outra abordagem

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

Para Mac:

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

Se se quiser um sinal quando atinge o zero, pode-se, por exemplo, construí-lo com um comando que devolva um estado de saída não zero a zero e combiná-lo com watch -b, ou algo assim, mas se se quiser construir um guião mais elaborado, este provavelmente não é o caminho a seguir; é mais uma solução do tipo “rápida e suja de uma linha”.


Eu gosto do programa watch em geral. Vi-o pela primeira vez depois de já ter escrito incontáveis loops while sleep 5; do para efeitos diferentes. watch foi demonstravelmente mais agradável.

3
3
3
2017-06-23 21:06:54 +0000

O sw é um simples cronómetro que irá funcionar para sempre.

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

Instalação

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

Utilização

# Utilização

0x1&

1
1
1
2015-04-13 12:34:57 +0000

Finja que é uma pessoa no OSX à procura de um cronómetro de linha de comando. Finja que não quer instalar as ferramentas gnu e apenas quer correr com o unix date

nesse caso faça como diz @terdon, mas com esta modificação:

function stopwatch(){
    date1=`date +%s`; 
    while true; do 
        echo -ne "$(date -jf "%s" $((`date +%s` - $date1)) +%H:%M:%S)\r"; 
        sleep 0.1
    done
}
1
1
1
2019-04-13 14:58:34 +0000

Veja TermTime , é um bom relógio e cronómetro baseado em terminais:

pip install termtime

1
1
1
2015-06-02 01:12:11 +0000

Basta usar relógio + data na hora UTC. Também se pode instalar algum pacote para grande visualização…

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'

Experimente!

Veja também http://www.cyberciti.biz/faq/create-large-colorful-text-banner-on-screen/

1
1
1
2014-09-26 15:21:48 +0000

Para referência futura, existe uma ferramenta de linha de comando chamada µTimer com opções de linha de comando muito simples para um temporizador de contagem decrescente/contínuo.

1
1
1
2014-02-13 12:00:38 +0000

Um exemplo 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()

0
0
0
2018-11-05 13:49:26 +0000

Uma versão GUI do cronómetro

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
0
0
0
2016-12-08 20:20:14 +0000

Encontrei esta pergunta hoje cedo, quando procurei uma aplicação de termo para exibir um grande contador decrescente para uma oficina. Nenhuma das sugestões era exactamente o que eu precisava, por isso juntei rapidamente outra em Go: https://github.com/bnaucler/cdown

Como a pergunta já está suficientemente respondida, considere que isto é para bem da posteridade.

0
0
0
2017-01-24 23:04:07 +0000

$ 1500 && xterm -fg amarelo -g 240x80 &

Quando aquele grande terminal com texto amarelo salta, está na hora de se levantar e esticar!

Notas: - 1500 segundos = 25 minutos pomodoro - 240x80 = tamanho do terminal com linha de 240 caracteres, e 80 filas. Preenche um ecrã para mim de forma perceptível.

Crédito: http://www.linuxquestions.org/questions/linux-newbie-8/countdown-timer-for-linux-949463/

0
0
0
2016-04-20 15:14:05 +0000

Isto é semelhante à resposta aceite, mas terdon’s countdown()gave me erros de sintaxe. Este funciona bem para mim, no entanto:

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!"; } .bashrc

Pode colocá-lo em timer t e depois executá-lo com: 0x6&& (onde t é tempo em minutos).

-2
-2
-2
2014-08-18 17:19:37 +0000

Se quiser um programa compilável por qualquer razão, o seguinte funcionaria:

#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 << "0x1&33[2A0x1&33[K";
    std::this_thread::sleep_for(milliseconds(100));
  }
  std::cout << "Finished" << std::endl;
  return 0;
}

Isto pode ser utilizado noutros programas também e facilmente portado, se um ambiente de bash não estiver disponível ou se apenas preferir utilizar um programa compilado github