Is er een manier om een aftel- of stopwatch-timer in een terminal weer te geven?
Hoe kan ik een real-time countdown timer weergeven op de Linux terminal? Is er een bestaande app of, nog beter, een one liner om dit te doen?
Hoe kan ik een real-time countdown timer weergeven op de Linux terminal? Is er een bestaande app of, nog beter, een one liner om dit te doen?
Ik weet niet waarom je beep
nodig hebt, als je alleen een stopwatch wilt, kun je dit doen:
while true; do echo -ne "`date`\r"; done
Dat laat je de seconden zien die in realtime verstrijken en je kunt het stoppen met Ctrl+C. Als je meer precisie nodig hebt, kun je dit gebruiken om je nanoseconden te geven:
while true; do echo -ne "`date +%H:%M:%S:%N`\r"; done
Tenslotte, als je echt, echt “stopwatch formaat” wilt, waar alles begint bij 0 en begint te groeien, zou je iets als dit kunnen doen:
date1=`date +%s`; while true; do
echo -ne "$(date -u --date @$((`date +%s` - $date1)) +%H:%M:%S)\r";
done
Voor een afteltimer (waar je oorspronkelijke vraag niet om vroeg) zou je dit kunnen doen (verander de seconden dienovereenkomstig):
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
Je kunt deze combineren tot eenvoudige commando’s door bash (of welke shell je ook verkiest) functies te gebruiken. Voeg in bash deze regels toe aan je ~/.bashrc
(de sleep 0.1
zorgt ervoor dat het systeem 1/10e seconde wacht tussen elke run, zodat je je CPU niet overbelast):
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
}
Je kunt dan een afteltimer van een minuut starten door te draaien:
countdown 60
Je kunt twee uur aftellen met:
countdown $((2*60*60))
of een hele dag met:
countdown $((24*60*60))
En de stopwatch starten met:
stopwatch
Als je zowel met dagen als met uren, minuten en seconden moet kunnen omgaan, zou je iets als dit kunnen doen:
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
}
Noteer dat de stopwatch
functie niet getest is voor dagen omdat ik er niet echt 24 uur op wilde wachten. Het zou moeten werken, maar laat het me alsjeblieft weten als het niet werkt.
sh-3.2# man leave
stel een timer in voor 15 minuten
sh-3.2# leave +0015
Alarm set for Thu Nov 3 14:19:31 CDT 2016. (pid 94317)
sh-3.2#
edit: Ik had een heleboel links open staan, en ik dacht dat dit specifiek voor osx was, sorry daarvoor. Ik laat mijn antwoord achter zodat anderen op de hoogte zijn van het verlof op de BSDs.
Ik heb deze gebruikt:
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
)
Voorbeeld:
countdown "00:07:55"
Hier is een bron .
Dit is voor een stopwatch met honderdsten van seconden:
#!/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
}
}
Kort antwoord:
for i in `seq 60 -1 1` ; do echo -ne "\r$i " ; sleep 1 ; done
Uitleg:
Ik weet dat er veel antwoorden zijn, maar ik wil gewoon iets posten dat heel dicht bij de vraag van OP ligt, dat ik persoonlijk zou accepteren als inderdaad “ oneliner countdown in terminal”. Mijn doelen waren:
Hoe het werkt:
seq
drukt getallen af van 60 tot 1. echo -ne "\r$i "
brengt de caret terug naar het begin van de string en drukt de huidige $i
waarde af. Een spatie erna is nodig om de vorige waarde te overschrijven, als die langer was met tekens dan de huidige $i
(10 - 9).Ik heb het zeer goede antwoord van terdon gecombineerd, in functie die tegelijkertijd de tijd sinds begin en tijd tot einde weergeeft. Er zijn ook drie varianten, zodat het gemakkelijker aan te roepen is (je hoeft geen bash wiskunde te doen), en het is ook geabstraheerd. Gebruiksvoorbeeld :
{ ~ } » 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
En zoiets als werk timer:
{ ~ } » 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
En als je een hele specifieke tijd nodig hebt:
{ ~ } » 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
Hier is de code om in je . 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]}))
}
Combineer dit met een manier om geluid af te spelen in linux terminal speel mp3 of wav bestand af via Linux command line ) of cygwin (cat /path/foo.wav > /dev/dsp
werkt voor mij in babun/win7) en je hebt een simpele flexibele timer met alarm!
Ik eindigde met het schrijven van mijn eigen shell script: (https://gist.github.com/tir38/5855000)
#!/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
Het verbaast me dat niemand de sleepenh
tool heeft gebruikt in hun scripts. In plaats daarvan gebruiken de voorgestelde oplossingen ofwel een sleep 1
tussen opeenvolgende timer outputs ofwel een busy loop die zo snel mogelijk output. De eerste is ontoereikend omdat door de kleine tijd die het afdrukken in beslag neemt, de uitvoer in werkelijkheid niet eenmaal per seconde zal gebeuren maar iets minder dan dat, wat suboptimaal is. Als er genoeg tijd verstreken is, zal de teller een seconde overslaan. Dit laatste is onvoldoende omdat het de CPU zonder goede reden bezig houdt.
De tool die ik in mijn $PATH
heb ziet er als volgt uit:
#!/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
Het script kan worden gebruikt als een stopwatch (aftellend tot het wordt onderbroken) of als een timer die gedurende de opgegeven tijd loopt. Aangezien het commando sleep
wordt gebruikt, kan met dit script de tijdsduur worden opgegeven waarvoor geteld moet worden, met dezelfde precisie als uw sleep
toestaat. Op Debian en afgeleiden omvat dit slaapstanden van subseconden en een mooie menselijk leesbare manier om de tijd op te geven. Dus je kunt bijvoorbeeld zeggen:
$ time countdown 2m 4.6s
countdown 2m 4.6s 0.00s user 0.00s system 0% cpu 2:04.60 total
En zoals je kunt zien, liep het commando precies gedurende 2 minuten en 4,6 seconden, zonder veel magie in het script zelf.
EDIT :
Het sleepenh gereedschap komt uit het gelijknamige pakket in Debian en zijn afgeleiden zoals Ubuntu. Voor distributies die het niet hebben, komt het uit https://github.com/nsc-deb/sleepenh
Het voordeel van sleepenh is, dat het in staat is om rekening te houden met de kleine vertraging die zich in de loop van de tijd ophoopt door het verwerken van andere dingen dan de slaap tijdens een loop. Zelfs als men gewoon 10 keer sleep 1
in een lus zou doen, zou de totale uitvoering iets meer dan 10 seconden duren vanwege de kleine overhead die komt van het uitvoeren van sleep
en het itereren van de lus. Deze fout stapelt zich langzaam op en zou na verloop van tijd onze stopwatch timer steeds onnauwkeuriger maken. Om dit probleem op te lossen, moet je bij elke iteratie van de lus de precieze tijd om te slapen berekenen, die gewoonlijk iets minder dan een seconde is (voor intervaltimers van een seconde). Het gereedschap sleepenh doet dit voor je.
Een andere aanpak
countdown=60 now=$(date +%s) watch -tpn1 echo '$((now-$(date +%s)+countdown))'
Voor Mac:
countdown=60 now=$(date +%s) watch -tn1 echo '$((now-$(date +%s)+countdown))'
#no p option on mac for watch
Als men een signaal wil als het op nul komt, zou men het bijvoorbeeld kunnen bouwen met een commando dat een niet-nul exit-status teruggeeft bij nul en het combineren met watch -b
, of zoiets, maar als men een meer uitgebreid script wil bouwen, is dit waarschijnlijk niet de manier om te gaan; het is meer een “quick and dirty one-liner” type oplossing.
Ik vind het watch
programma in het algemeen leuk. Ik zag het voor het eerst nadat ik al ontelbare while sleep 5; do
loops had geschreven voor verschillende effecten. watch
was aantoonbaar mooier.
is een eenvoudige stopwatch die eeuwig loopt.
wget -q -O - http://git.io/sinister | sh -s -- -u https://raw.githubusercontent.com/coryfklein/sw/master/sw
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
Doe alsof je een persoon bent op OSX die op zoek is naar een command line stopwatch. Stel dat je de gnu tools niet wilt installeren en gewoon met de unix date
wilt werken, doe in dat geval wat @terdon zegt maar met deze wijziging:
function stopwatch(){
date1=`date +%s`;
while true; do
echo -ne "$(date -jf "%s" $((`date +%s` - $date1)) +%H:%M:%S)\r";
sleep 0.1
done
}
Gebruik gewoon horloge + datum in UTC-tijd. Je kunt ook een of ander pakket installeren voor een groot scherm…
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'
Probeer het!
Zie ook http://www.cyberciti.biz/faq/create-large-colorful-text-banner-on-screen/
Een python voorbeeld:
#!/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()
Een GUI-versie van de stopwatch
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
Ik vond deze vraag eerder vandaag, toen ik op zoek was naar een term applicatie om een grote aftelklok weer te geven voor een workshop. Geen van de suggesties was precies wat ik nodig had, dus heb ik snel een andere in elkaar gezet in Go: https://github.com/bnaucler/cdown
Aangezien de vraag al voldoende beantwoord is, beschouw dit als voor het nageslacht.
$ sleep 1500 && xterm -fg yellow -g 240x80 &
Als die grote terminal met gele tekst opspringt, tijd om op te staan en je uit te rekken!
Opmerkingen: - 1500 seconden = 25 minuten pomodoro - 240x80 = terminal grootte met 240 karakter rij, en 80 rijen. Vult een scherm voor mij merkbaar op.
Credit: http://www.linuxquestions.org/questions/linux-newbie-8/countdown-timer-for-linux-949463/
Dit is vergelijkbaar met het geaccepteerde antwoord, maar terdon’s countdown()
gaf me syntaxisfouten. Deze werkt echter geweldig voor mij:
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!"; }
Je kunt het in .bashrc
stoppen en dan uitvoeren met: timer t
(waarbij t de tijd in minuten is).
Als je om wat voor reden dan ook een compileerbaar programma wilt, zou het volgende kunnen werken:
#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;
}
Dit kan ook in andere programma’s gebruikt worden en gemakkelijk geport worden, als een bash omgeving niet beschikbaar is of als je gewoon liever een gecompileerd programma gebruikt github