Czy istnieje sposób wyświetlenia odliczania lub stopera w terminalu?


144

Jak wyświetlić licznik czasu rzeczywistego na terminalu Linux? Czy istnieje już taka aplikacja, a jeszcze lepiej jedna linijka?

Odpowiedzi:


184

Nie jestem pewien, dlaczego potrzebujesz beep, jeśli wszystko, czego potrzebujesz, to stoper, możesz to zrobić:

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

To pokaże sekundy w czasie rzeczywistym i możesz to zatrzymać za pomocą Ctrl+ C. Jeśli potrzebujesz większej precyzji, możesz użyć tego, aby uzyskać nanosekundy:

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

Wreszcie, jeśli naprawdę chcesz naprawdę „formatu stopera”, w którym wszystko zaczyna się od 0 i zaczyna rosnąć, możesz zrobić coś takiego:

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

W przypadku licznika czasu (który nie jest tym, o co pytałeś w pierwotnym pytaniu) możesz to zrobić (odpowiednio zmień sekundy):

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

Możesz łączyć je w proste polecenia, używając funkcji bash (lub dowolnej powłoki, którą preferujesz). W bash dodaj te wiersze do swojego ~/.bashrc( sleep 0.1spowoduje to, że system będzie czekał przez 1/10 sekundy między każdym uruchomieniem, abyś nie spamował procesora):

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
}

Następnie możesz uruchomić minutnik odliczający minutę, uruchamiając:

countdown 60

Możesz odliczać dwie godziny dzięki:

countdown $((2*60*60))

lub cały dzień przy użyciu:

countdown $((24*60*60))

I uruchom stoper, uruchamiając:

stopwatch

Jeśli potrzebujesz umieć radzić sobie z dniami, godzinami, minutami i sekundami, możesz zrobić coś takiego:

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
}

Pamiętaj, że stopwatchfunkcja nie była testowana od wielu dni, ponieważ tak naprawdę nie chciałem czekać na nią 24 godziny. Powinien działać, ale proszę dać mi znać, jeśli nie działa.


9
Dodałem te ładne funkcje do mojego .zshrczaraz po przeczytaniu twojej odpowiedzi. Dzisiaj użyłem countdownpierwszy raz i zauważyłem dość wysokie zużycie procesora. Dodałem sleep 0.1(nie wiem, czy czas uśpienia ułamka sekundy jest obsługiwany we wszystkich systemach), co znacznie to poprawiło. Wadą jest oczywiście mniej dokładna dokładność wyświetlania, ale mogę żyć z odchyleniem maks. 100ms.
mpy

@ moje dzięki, że o tym wspomniałeś. Dostaję ~ 3% użycia procesora, kiedy to robię bash, mogę z tym żyć (chociaż jest to wyższe niż się spodziewałem i dodałem też sen do własnego .bashrc).
terdon

3
Właśnie znalazłem tę odpowiedź. Odkryłem, że umieszczenie znaku powrotu karetki na początku instrukcji echa w funkcji stopera było przydatne, ponieważ oznaczało, że zabicie stopera nie nadpisało aktualnego czasu stopera: echo -ne "\ r $ (data -u --data @ $ (( date +%s- $ data1)) +% H:% M:% S) ";
mkingston

3
@chishaku: W systemie OS X wydaje się, że to działa dla mnie: echo -ne "$(date -ju -f %s $(($date1 - data +% s )) +%H:%M:%S)\r";
user1071847,

1
Z pakietu sox Dodam piękny dźwięk do odtworzenia po zakończeniu odliczania: play -q -n synth 2 pluck C5.
Pablo A

94

Mój ulubiony sposób to:

Początek:

time cat

Zatrzymać:

ctrl+c

Jak skomentował @wjandrea poniżej, należy uruchomić inną wersję:

time read

i naciśnij, Enteraby zatrzymać



8
podobnie, ale możesz nacisnąć klawisz Enter, aby go zatrzymać:time read
wjandrea

10
time readkończy się niepowodzeniem w Zsh, ale time (read)działa.
Sparhawk

Problem polega jednak na tym, że nie można zobaczyć czasu bez jego anulowania lub zakończenia. Po ponownym uruchomieniu licznik zaczyna się od nowa.
Zelphir Kaltstahl

38

Szukałem tego samego i ostatecznie napisałem coś bardziej skomplikowanego w Pythonie:

To da ci proste 10-sekundowe odliczanie:

sudo pip install termdown
termdown 10

Źródło: https://github.com/trehn/termdown


1
@DoktoroReichard: To jest link do pobrania.
harrymc

1
@ Suhaib: To powinno i robi dla mnie. Podnieś problem na GitHub, podając więcej informacji.
trehn

1
Uwielbiam to - to właśnie moja droga
Wayne Werner

1
Bardzo fajnie, podoba mi się ASCII
Guillermo

1
To jest naprawdę fajne! 😄
orschiro

13

Użyłem tego:

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
)

Przykład:

 countdown "00:07:55"

Oto źródło .


2
Zgodny z POSIX - działa na OS X :)
djule5

13
sh-3.2# man leave

ustawić minutnik na 15 minut

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

edytuj: Miałem kilka otwartych linków i pomyślałem, że to jest specyficzne dla OSX, przepraszam za to. Pozostawiając moją odpowiedź, aby inni byli świadomi urlopu na BSD.


1
Leave działa również w Linuksie, ale najpierw musisz zainstalować program Leave z domyślnych repozytoriów.
karel

6

To jest dla stopera z setnymi sekund:

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

Przykład


Ładne rozwiązanie tylko dla Linuksa! Uwielbiam brak połączeń zewnętrznych. Zauważ, że mój system Debian ma dwie wartości w / proc / uptime, a druga prawdopodobnie odnosi się do mojego poprzedniego uptime. Skrypt ten można dostosować, aby temu zaradzić, zmieniając wiersz 5 nareturn $1
Adam Katz

4

Połączyłem bardzo dobrą odpowiedź terdona, w funkcję, która jednocześnie wyświetla czas od początku i czas do końca. Istnieją również trzy warianty, więc łatwiej jest zadzwonić (nie musisz robić matematyki), a także jest abstrakcyjne. Przykład zastosowania :

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

I coś w stylu timera pracy:

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

A jeśli potrzebujesz bardzo konkretnego czasu:

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

Oto kod do umieszczenia w .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]})) 
}

Połącz to z jakimś sposobem odtwarzania dźwięku w terminalu linuksowym ( odtwarzaj pliki mp3 lub wav za pomocą wiersza poleceń Linuksa ) lub cygwin ( cat /path/foo.wav > /dev/dsp działa dla mnie w babun / win7) i masz prosty elastyczny zegar z alarmem !


4

Inne podejście

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

Dla Maca:

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

Jeśli ktoś chce otrzymać sygnał, gdy osiągnie zero, może np. Zbudować go za pomocą polecenia, które zwróciło niezerowy status wyjścia na zero i połączyć go z watch -bczymś innym, ale jeśli chce się zbudować bardziej skomplikowany skrypt, to prawdopodobnie nie taka droga; jest to bardziej „szybkie i brudne rozwiązanie typu single-liner”.


watchOgólnie podoba mi się ten program. Po raz pierwszy to zobaczyłem po tym, jak napisałem już niezliczoną liczbę while sleep 5; dopętli do różnych efektów. watchbył wyraźnie ładniejszy.


3

W końcu napisałem własny skrypt powłoki: 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 

1
Niezły skrypt, +1. Po prostu wiesz, że to jest odliczanie czasu, a nie stoper.
terdon

ha masz rację, tego naprawdę chciałem. Zaktualizuję moje nazewnictwo.
tir38

3

Dziwi mnie, że nikt nie używał tego sleepenhnarzędzia w swoich skryptach. Zamiast tego proponowane rozwiązania wykorzystują albo sleep 1pomiędzy kolejnymi wyjściami timera, albo zajętą ​​pętlą, która wysyła tak szybko, jak to możliwe. Ten pierwszy jest nieodpowiedni, ponieważ z uwagi na krótki czas drukowania, wydruk nie będzie się odbywał raz na sekundę, ale będzie nieco mniejszy niż ten, który nie jest optymalny. Po upływie wystarczającego czasu licznik przeskoczy o sekundę. Ta ostatnia jest nieodpowiednia, ponieważ powoduje, że procesor jest zajęty bez powodu.

Narzędzie, które mam, $PATHwygląda następująco:

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

Skrypt może być używany jako stoper (odliczanie do przerwania) lub jako licznik czasu, który działa przez określony czas. Ponieważ sleeppolecenie jest używane, ten skrypt pozwala określić czas, przez który należy liczyć z taką samą dokładnością, jak sleeppozwala. W przypadku Debiana i pochodnych obejmuje to snu poniżej sekundy i miły, czytelny dla człowieka sposób określania czasu. Na przykład możesz powiedzieć:

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

Jak widać, polecenie działało dokładnie przez 2 minuty i 4,6 sekundy, bez dużej ilości magii w samym skrypcie.

EDYCJA :

Narzędzie sleepenh pochodzi z pakietu o tej samej nazwie w Debianie i jego pochodnych, takich jak Ubuntu. W przypadku dystrybucji, które go nie mają, pochodzi z https://github.com/nsc-deb/sleepenh

Zaletą Sleepenh jest to, że jest w stanie wziąć pod uwagę niewielkie opóźnienie, które kumuluje się w czasie od przetwarzania innych rzeczy niż sen podczas pętli. Nawet jeśli ktoś sleep 1wykona tylko pętlę 10 razy, ogólne wykonanie zajmie trochę więcej niż 10 sekund z powodu niewielkiego narzutu związanego z wykonywaniem sleepi iteracją pętli. Ten błąd powoli narasta i z czasem sprawi, że nasz stoper będzie coraz bardziej nieprecyzyjny. Aby rozwiązać ten problem, każda iteracja pętli musi obliczyć dokładny czas uśpienia, który zwykle jest nieco krótszy niż sekunda (dla timerów interwału 1-sekundowego). Narzędzie Sleepenh robi to za Ciebie.


Nie rozumiem, jakie korzyści daje to w porównaniu z moją odpowiedzią, która również wykorzystuje sleep 0.1. Co to jest sleepnh(nie mogę go znaleźć w repozytoriach Arch) i czym się różni sleep? O ile mogę stwierdzić, zasadniczo robisz to samo, co moja odpowiedź powyżej. czego mi brakuje?
terdon

@terdon Sleepenh pochodzi stąd github.com/nsc-deb/sleepenh Problem z powiedzeniem sleep 5polega na tym, że nie śpisz dokładnie przez 5 sekund. Spróbuj na przykład time sleep 5i zobaczysz, że uruchomienie polecenia zajmuje nieco ponad 5 sekund. Z czasem błędy się kumulują. Narzędzie Sleepenh pozwala łatwo uniknąć gromadzenia się błędów.
josch

DOBRZE. W moim systemie widzę błąd 0,002 sekundy. Naprawdę wątpię, aby ktokolwiek użyłby tego rodzaju narzędzia i spodziewałby się lepszej dokładności niż milisekunda, ale byłoby lepiej, gdybyś przynajmniej edytował swoją odpowiedź i ja) wyjaśnił, dlaczego sleepnhjest lepszy niż sleep(mówisz tylko, że inne odpowiedzi używają sleep 1- a których nie , wykorzystuje to tylko OP) i ii) skąd go pobrać i jak go zainstalować, ponieważ nie jest to standardowe narzędzie.
terdon

1
@terdon I wyjaśnił różnicę pomiędzy sleeporaz sleepenhw pierwszym akapicie. W każdym razie, prawdopodobnie nie byłem wystarczająco jasny, więc rozwinąłem to bardziej na końcu. Problemy z dokładnością co do milisekund są takie same, jak w przypadku sleepjednorazowego połączenia . Gromadzą się one z czasem i w pewnym momencie jest to zauważalne. Nie powiedziałem, że inni używają tylko sleep 1. Powiedziałem, że używają sleep 1albo busyloop. Co oni nadal robią. Pokaż mi licznik. Odpowiedzi, które sleep 0.1to robią, są takie same, jak te, sleep 1z wyjątkiem tego, że kumulują błędy jeszcze szybciej.
josch

Znalazłem odpowiedzi szukając kogoś, kto przynajmniej uzna istnienie problemu, który rozwiązałeś.
mariotomo

2

Krótka odpowiedź:

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

Wyjaśnienie:

Wiem, że jest wiele odpowiedzi, ale chcę tylko napisać coś bardzo zbliżonego do pytania OP, które osobiście zaakceptowałbym jako „ odliczanie onelinera w terminalu ”. Moimi celami były:

  1. Jedna wkładka.
  2. Odliczanie
  3. Łatwa do zapamiętania i pisania w konsoli (bez funkcji i logiki, tylko bash).
  4. Nie wymaga instalowania dodatkowego oprogramowania (można go używać na dowolnym serwerze, przez który przechodzę przez ssh, nawet jeśli nie mam roota).

Jak to działa:

  1. seq drukuje liczby od 60 do 1.
  2. echo -ne "\r$i "zwraca daszek na początek łańcucha i wypisuje bieżącą $iwartość. Spacja po nim jest wymagana do zastąpienia poprzedniej wartości, jeśli była dłuższa o znaki niż bieżąca $i(10 -> 9).

1
Działa to najlepiej w moim przypadku użycia w systemie Mac OS do użycia w skrypcie bash. Wyjaśnienie, jak to działa, jest bardzo pomocne.
James Campbell,

1

Do wykorzystania w przyszłości istnieje narzędzie wiersza polecenia o nazwie µTimer z bardzo prostymi opcjami wiersza poleceń dla licznika odliczania / odliczania.


1

Udawaj, że jesteś osobą w systemie OSX i szukasz stopera z linii poleceń. Udawaj, że nie chcesz instalować narzędzi GNU, a po prostu chcesz działać z Uniksemdate

w takim przypadku postępuj zgodnie z instrukcjami @terdon, ale z tą modyfikacją:

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
Próbowałem na OS X El Capitan, z jakiegoś powodu zaczyna się o 16:00:00
nopole

1

Wystarczy użyć zegarka + daty w czasie UTC. Możesz także zainstalować pakiet dla dużego wyświetlacza ...

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'

Spróbuj!

Zobacz także http://www.cyberciti.biz/faq/create-large-colorful-text-banner-on-screen/


1

sw to prosty stoper, który będzie działał wiecznie.

południowy zachód

zainstalować

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

Stosowanie

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

1

Przykład 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()

próbny



0

Jest to podobne do przyjętej odpowiedzi, ale terdon countdown()dał mi błędy składniowe. Ten działa jednak dla mnie świetnie:

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

Możesz go włożyć, .bashrca następnie wykonać za pomocą: timer t(gdzie t to czas w minutach).


0

Znalazłem to pytanie dzisiaj, szukając terminowej aplikacji do wyświetlania dużego licznika czasu dla warsztatu. Żadna z sugestii nie była dokładnie tym, czego potrzebowałem, więc szybko przygotowałem kolejną w Go: https://github.com/bnaucler/cdown

Ponieważ odpowiedź na to pytanie jest już wystarczająca, rozważ to dla potomności.



0

Wersja GUI stopera

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

-2

Jeśli chcesz program kompilowany z dowolnego powodu, działałyby następujące czynności:

#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;
}

Można tego użyć w innych programach, a także łatwo przenosić, jeśli środowisko bash nie jest dostępne lub po prostu wolisz używać skompilowanego programu

github

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.