How can I display a real-time countdown timer on the Linux terminal? Is there an existing app or, even better, a one liner to do this?
-
In case, you don't know how long it will take, just add a spinner that exits, once the command is done: https://unix.stackexchange.com/a/92925/20661 – rubo77 Jan 10 '21 at 03:05
33 Answers
I'm not sure why you need beep. If all you want is a stopwatch, you can do this:
while true; do printf '%s\r' "$(date)"; done
That will show you the seconds passing in realtime and you can stop it with Ctrl+C. If you need greater precision, you can use this to give you nanoseconds:
while true; do printf '%s\r' "$(date +%H:%M:%S:%N)"; done
Finally, if you really, really want "stopwatch format", where everything starts at 0 and starts growing, you could do something like this:
start=$(date +%s)
while true; do
time="$(($(date +%s) - $start))"
printf '%s\r' "$(date -u -d "@$time" +%H:%M:%S)"
done
For a countdown timer (which is not what your original question asked for) you could do this (change seconds accordingly):
seconds=20
start="$(($(date +%s) + $seconds))"
while [ "$start" -ge `date +%s` ]; do
time="$(( $start - `date +%s` ))"
printf '%s\r' "$(date -u -d "@$time" +%H:%M:%S)"
done
You can combine these into simple commands by using bash (or whichever shell you prefer) functions.
In bash, add these lines to your ~/.bashrc (the sleep 0.1 will make the system wait for 1/10th of a second between each run so you don't spam your CPU):
countdown() {
start="$(( $(date '+%s') + $1))"
while [ $start -ge $(date +%s) ]; do
time="$(( $start - $(date +%s) ))"
printf '%s\r' "$(date -u -d "@$time" +%H:%M:%S)"
sleep 0.1
done
}
stopwatch() {
start=$(date +%s)
while true; do
time="$(( $(date +%s) - $start))"
printf '%s\r' "$(date -u -d "@$time" +%H:%M:%S)"
sleep 0.1
done
}
You can then start a countdown timer of one minute by running:
countdown 60
You can countdown two hours with:
countdown "$((2 * 60 * 60))"
or a whole day using:
countdown "$((24 * 60 * 60))"
And start the stopwatch by running:
stopwatch
If you need to be able to deal with days as well as hours, minutes and seconds, you could do something like this:
countdown() {
start="$(( $(date +%s) + $1))"
while [ "$start" -ge $(date +%s) ]; do
## Is this more than 24h away?
days="$(($(($(( $start - $(date +%s) )) * 1 )) / 86400))"
time="$(( $start - `date +%s` ))"
printf '%s day(s) and %s\r' "$days" "$(date -u -d "@$time" +%H:%M:%S)"
sleep 0.1
done
}
stopwatch() {
start=$(date +%s)
while true; do
days="$(($(( $(date +%s) - $start )) / 86400))"
time="$(( $(date +%s) - $start ))"
printf '%s day(s) and %s\r' "$days" "$(date -u -d "@$time" +%H:%M:%S)"
sleep 0.1
done
}
Note that the stopwatch function hasn't been tested for days since I didn't really want to wait 24 hours for it. It should work, but please let me know if it doesn't.
- 52,568
- 14
- 124
- 170
-
12I added these nice functions to my `.zshrc` right after I read your answer. Today I used `countdown` the first time and noticed a rather high CPU usage. I added a `sleep 0.1` (I don't know if a sleep time of a fractional second is supported on all systems) which improved that a lot. The drawback is of course a less accurate display accuracy, but I can live with a deviation of max. 100ms. – mpy Jul 05 '13 at 14:45
-
@mpy thanks for mentioning that. I am getting ~3% CPU usage when doing this in `bash`, I can live with that (though it _is_ higher than I expected and I have also added the sleep to my own .bashrc). – terdon Jul 05 '13 at 14:59
-
@terdon: I must admit that I used it on a rather old machine (2007?!) and CPU went up to 18%... otherwise I probably wouldn't have noticed. – mpy Jul 05 '13 at 15:02
-
5Just found this answer. I found putting the carriage return at the beginning of the echo statement in the stopwatch function was handy as it meant killing the stopwatch didn't overwrite the current stopwatch time: echo -ne "\r$(date -u --date @$((`date +%s` - $date1)) +%H:%M:%S)"; – mkingston Jun 16 '14 at 12:51
-
Happy to help. But rather more importantly, thank you for the code :) – mkingston Jun 16 '14 at 12:53
-
Would the code be different on osx? I'm getting a 'date: illegal option' error – chishaku Sep 29 '14 at 17:50
-
2@chishaku yes, the OSX `date` command [doesn't have the `-d` option](https://developer.apple.com/library/mac/documentation/Darwin/Reference/ManPages/man1/date.1.html). Well, it does, but it's for something else. You might be able to do something with `-v` but I don't have a mac (or access to BSD `find`) so I can't really help. – terdon Sep 29 '14 at 18:05
-
Do you have any hint to display times bigger then 24hours? I tried to display even the day of year (%j option) but this is biased by 1 day – Alepac Aug 25 '15 at 14:50
-
-
Thanks for answer! Any suggestion on how to add the timer after the path? like: `name@pc:folder[countdown]`, I would like to have a pomodoro stopwatch in terminal... – teone Sep 23 '15 at 15:09
-
@teone yes, you could set your `PS1` variable to call the timer but what would it be counting? The time since _what_? Would it be reset each time a prompt is shown? This sounds like it should be a new question, either here or on [unix.se]. Post it, explain exactly what you need, what you expect the counter to be counting and leave me a comment here. I'll see what I can do. – terdon Sep 23 '15 at 15:43
-
@terdon The countdown will run forever if the script hangs for more than a second (for whatever reason). The while condition checks for equality (not less than) and _might never_ be triggered. You can test this yourself: run `(countdown 5)`, then press CTRL-Z, then after a few seconds enter `fg`. The timer will continue counting down from `23:59:59`. – jmiserez Nov 13 '15 at 20:10
-
3@chishaku: On OS X, this seemed to work for me: `echo -ne "$(date -ju -f %s $(($date1 - `date +%s`)) +%H:%M:%S)\r"`; – user1071847 Jul 11 '16 at 16:26
-
When I notice myself writing things like `$(($(($(( ...` I usually start thinking "I should probably use another language" (: – jwd Jan 06 '17 at 00:34
-
I've been using the third one (date1=) and getting 10% CPU usage on an i7 Sandybridge which sets the fans off and I'm assuming hits the battery too. – TenLeftFingers Jan 26 '17 at 11:50
-
@TenLeftFingers well, yes. That's why I included the ones further down and explain that they are lighter on the system. – terdon Jan 26 '17 at 12:24
-
@terdon My bad. Thank you, that reduces CPU consumption to 1% for me. – TenLeftFingers Jan 27 '17 at 13:06
-
Re @user1071847 s comment about, comment formatting seems to have stripped the backticks surrounding ``date +%s`` just before the double end parens )). Putting those in place after a copy/paste makes it work just fine. – TurtlePowered Oct 14 '17 at 08:27
-
So good :-) and really well explained and elaborated. I like the fact that my shit 15 years old becomed with radio and chronometer, and my new computer still comes with no radio and no chronometer (even if has ultra precise counters for time managin). I could not understand why such elementary tools are not provided within a Operating System. – m3nda Oct 29 '17 at 03:29
-
1With [sox package](https://packages.ubuntu.com/search?keywords=sox) I would add a nice sound to play at the end of the countdown: `play -q -n synth 2 pluck C5`. – Pablo A May 15 '18 at 23:59
-
You can use `watch` instead of the while loop. For 1-second resolution the stopwatch becomes this one-liner: `date1=$(date +%s) watch -n 1 echo '$(date -u --date @$(($(date +%s) - date1)) +%H:%M:%S )'` For finer resolution, you can add `-n 0.1` but then also update the calculation to use nanoseconds. – Max Murphy Jan 03 '19 at 15:55
-
@terdon can you post an answer that also works on a Mac? I tried the line `echo -ne "$(date -ju -f %s $(($date1 - date +%s)) +%H:%M:%S)\r"` and it didn't work – nonopolarity Dec 04 '20 at 14:17
-
@nonopolarity sorry, no. Macs have [limited versions](https://ss64.com/osx/date.html) of the various tools compared to the standard Linux coreutils because macOS comes from BSD. However, if you install GNU date, this should work for you, but I can't help since I don't use macs. – terdon Dec 04 '20 at 14:34
-
I found an answer in https://superuser.com/questions/850368/osx-bash-command-line-countdown-timer/1607383#1607383 and it worked. I guess counting down for more than a day (and displaying the number of days if it is more than a day) would be more complete, but I guess not very often do people count down for more than a day – nonopolarity Dec 04 '20 at 18:16
-
-
@alper please stop suggesting the same edit. If you want, you can post a new answer, but there is no need for `function` keywords, nor `expr` (we're already in a math context) and I don't think you're right about the need for the -1 anyway. – terdon Sep 09 '21 at 11:54
-
Thanks for the edit @kelvin. There is no question about `printf` being better, but I am not sure about the `-d` vs `--date`. As far as I know, the `-d/--date` is only a feature of the GNU implementation of `date`, are there any `date` flavors that understand `-d` and not `--date`? – terdon Apr 06 '22 at 10:36
-
@terdon No problem. "There is no question about printf being better, but I am not sure about the -d vs --date" To be honest, I'm not 100% sure about that either. busybox `date` works with `--date`, but `busybox date --help` only mentions `-d`. The man page of netbsd `date` also only mentions `-d`, though I can't quite tell if it's equivalent (and if so, maybe it also works with `--date`). Given the documentation and that at least busybox tends to only implement what is "needed"/used in scripting (AFAIK), I'd assume `-d` to be the more portable option. – kelvin Apr 06 '22 at 11:02
-
1@kelvin that's more than enough, thanks. I thought busybox `date` didn't even support `-d`, and am very surprised (and pleased) to hear that both busybox and netBSD `date`s support it! As I said, I thought it was only a GNU thing, so even _one_ example that supports/mentions `-d` and not `--date` is enough to convince me :). – terdon Apr 06 '22 at 11:05
-
@terdon As another point of reference, it appears that `--date` is only supported if busybox is built with `ENABLE_LONG_OPTS` (enabled by default). "I thought busybox date didn't even support -d, and am very surprised (and pleased) to hear that both busybox and netBSD dates support it!" Nice, I'm sometimes positively surprised about what is supported on busybox as well (such as `xargs -0`). I personally use the intersection of functionality of GNU and busybox (and *BSD if possible) as a baseline when pure POSIX doesn't cut it. – kelvin Apr 06 '22 at 11:17
-
@terdon By the way, I'd like to make a few more edits related to whitespace, quoting and portability. Not sure if you'd agree with all of them, so I'm making separate edits. – kelvin Apr 06 '22 at 11:38
-
@kelvin no, please don't, that's much more work. There are loads of edits to do, for instance, I would replace all backticks with `$()` and we may as well quote the `$()` although not strictly necessary in this case, it's still a good habit. In my defense, I wrote this almost 10 years ago :) Anyway, feel free to make the edits, but please only do it once so I don't need to approve each separately. If I disagree with any of your suggestions, I can always edit them out. – terdon Apr 06 '22 at 12:01
-
@terdon "no, please don't, that's much more work." Alright, made all the edits at once. "I would replace all backticks with $()" Considering how frequently each loop is intended to run, to avoid unnecessary subshells I'd use backticks whenever command nesting is not used. I added the "time" variable to make things IMO more readable (and to have less lengthy lines), which also makes commands less nested. "In my defense, I wrote this almost 10 years ago :)" No worries, I'm mostly interested in potentially improving the .bashrc of future readers :p – kelvin Apr 06 '22 at 13:48
-
@kelvin thanks! I approved most of them. Note that there is [no difference](https://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html#tag_18_06_03) between `\`command\`` and `$(command)`, both run in subshells, the only difference is that the backticks are [harder to understand](https://unix.stackexchange.com/a/5782/22222) and there's really no good reason to use them in modern scripts. – terdon Apr 06 '22 at 14:24
-
@kelvin I rejected your latest edit since i) the quotes are not needed in those specific places and ii) I find `\rfoo` unintuitive compared to `foo\r` and, more importantly, adding the `\r` to the beginning means that any text typed by mistake will not be cleared. Unless you have more important fixes, bugs etc, I think this is good enough and we can stop here. – terdon Apr 07 '22 at 14:19
-
Let us [continue this discussion in chat](https://chat.stackexchange.com/rooms/135378/discussion-between-kelvin-and-terdon). – kelvin Apr 07 '22 at 14:21
-
-
1@BigMcLargeHuge because they add up. I figured if I sleep a full second, I will by definition need to wait a full second, _then_ do the calculations, so I will have less than a second's accuracy. Granted, worrying about such small deviations in a silly little shell script like this is a bit absurd, but there you go. – terdon Jul 18 '22 at 17:04
My favorite way is:
Start:
time cat
Stop:
ctrl+c
As @wjandrea commented below, another version is to run:
time read
and press Enter to stop
- 1,788
- 1
- 11
- 11
-
17
-
21
-
5Problem is though, that you cannot see the time without canceling it or finishing it. When you then restart it, the timer begins anew. – Zelphir Kaltstahl Oct 18 '17 at 08:50
I was looking for the same thing and ended up writing something more elaborate in Python:
This will give you a simple 10-second countdown:
pip install termdown
termdown 10
-
-
3@Suhaib: It should and does for me. Please raise an issue on GitHub with more info. – trehn Jun 27 '14 at 09:23
-
1
-
Much better answer than the accepted one for me, since the accepted answer uses a lot of CPU resources for a countdown. This one doesn't. – C26 Nov 10 '21 at 12:27
-
**Do not** use `sudo pip install` under any circumstances. You are liable to break your system's Python installation. If this tool is not available in your preferred package repo, use [Pipx](https://pypi.org/project/pipx/) to install "standalone" Python applications, or at least use `pip install --user`. – shadowtalker Jan 27 '22 at 05:39
Use leave (it at least works on BSD descendants):
man leave
Set a timer for 15 minutes:
leave +0015
Alarm set for Thu Nov 3 14:19:31 CDT 2016. (pid 94317)
- 12,090
- 23
- 70
- 90
- 469
- 4
- 3
-
2leave works in Linux too, but first you have to install the leave program from the default repositories. – karel Nov 04 '16 at 04:10
-
4
-
1it is nice, except currently it doesn't do seconds, so it is not possible to count down 30 seconds, for example – nonopolarity Dec 04 '20 at 10:56
-
Its a little weird, but works. Though I use `at` so it sends me a notify message: `at now + 4 minutes <
– Yarek T Jun 09 '23 at 13:29
Short answer:
for i in `seq 60 -1 1` ; do echo -ne "\r$i " ; sleep 1 ; done
Explanation:
I know there are a lot of answers, but I just want to post something very close to OP's question, that personally I would accept as indeed "oneliner countdown in terminal". My goals were:
- One liner.
- Countdown.
- Easy to remember and type in console (no functions and heavy logic, bash only).
- Does not require additional software to install (can be used on any server I go via ssh, even if I do not have root there).
How it works:
seqprints numbers from 60 to 1.echo -ne "\r$i "returns caret to beginning of the string and prints current$ivalue. Space after it is required to overwrite previous value, if it was longer by characters than current$i(10 -> 9).
- 321
- 2
- 6
-
2This worked best for my use case on Mac OS for use in a bash script. The explanation of how it works is extra helpful. – james-see Aug 12 '19 at 17:56
-
Other useful side effect: if the system is sent to standby, the timer is not (meaningfully) impacted. – Marcus May 01 '23 at 08:06
I've used this one:
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
)
Example:
countdown "00:07:55"
Here's a source.
- 2,649
- 2
- 28
- 34
-
3
-
error on arch linux: `countdown:4: bad math expression: operand expected at \`* 60 + '` – Chalist Dec 18 '19 at 01:03
-
-
Note that this solution is not 100% accurate: it assumes that "sleep 1 & printf" runs exactly 1 second every time, which is never true. If your system is too busy, your timer will be slow. Due to relativistic effects. – kolypto Aug 16 '21 at 15:36
I use this small Go program:
package main
import (
"fmt"
"time"
)
func format(d time.Duration) string {
mil := d.Milliseconds() % 1000
sec := int(d.Seconds()) % 60
min := int(d.Minutes())
return fmt.Sprintf("%v m %02v s %03v ms", min, sec, mil)
}
func main() {
t := time.Now()
for {
time.Sleep(10 * time.Millisecond)
s := format(time.Since(t))
fmt.Print("\r", s)
}
}
- 1
- 24
- 120
- 163
Another approach
countdown=60 now=$(date +%s) watch -tpn1 echo '$((now-$(date +%s)+countdown))'
For Mac:
countdown=60 now=$(date +%s) watch -tn1 echo '$((now-$(date +%s)+countdown))'
#no p option on mac for watch
If one wants a signal when it hits zero, one could e.g. build it with a command that returned a non-zero exit status at zero and combine it with watch -b, or something, but if one wants to build a more elaborate script, this is probably not the way to go; it is more of a "quick and dirty one-liner" type solution.
I like the watch program in general. I first saw it after I had already written countless while sleep 5; do loops to different effects. watch was demonstrably nicer.
- 113
- 5
- 23,895
- 5
- 57
- 61
sw is a simple stopwatch that will run forever.

Install
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
- 1,602
- 2
- 17
- 21
-
error on arch: `Try 'date --help' for more information. ate: invalid option -- 'v'` – Chalist Dec 18 '19 at 01:12
-
Why would install something whose URL contains *"[sinister](https://en.wiktionary.org/wiki/sinister#Adjective)"*? - *"2. Evil or seemingly evil; indicating lurking danger or harm."* – Peter Mortensen Mar 07 '20 at 18:06
-
1I agree, “sinister” was a horrible name choice for a software installer. – Cory Klein Mar 07 '20 at 20:56
I have combined terdon's very good answer, into a function which at the same time displays the time since the start, and the time till the end. There are also three variants, so it's easier to call (you don't have to do Bash math), and it's also abstracted.
Example of use:
{ ~ } » 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
And something like a work 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
And if you need some very specific time:
{ ~ } » 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
Here's the code to put into your .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 in some other Stack Exchange answer
{
a=( ${1//:/ })
echo $((${a[0]}*3600+${a[1]}*60+${a[2]}))
}
Combine this with some way of playing sound in linux terminal (Play MP3 or WAV file via the Linux command line) or Cygwin (cat /path/foo.wav > /dev/dsp works for me in Babun/Windows 7) and you have a simple flexible timer with alarm!
- 12,090
- 23
- 70
- 90
- 109
- 1
- 3
-
The Babun project [has been discontinued](http://babun.github.io/). – Peter Mortensen Mar 07 '20 at 17:44
I'm surprised that nobody used the sleepenh tool in their scripts. Instead, the proposed solutions either use a sleep 1 between subsequent timer outputs or a busy loop that outputs as fast as possible. The former is inadequate because due to the small time spent doing the printing, the output will not actually happen once per second but a bit less than that which is suboptimal. After enough time passed, the counter will skip a second. The latter is inadequate because it keeps the CPU busy for no good reason.
The tool that I have in my $PATH looks like this:
#!/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
The script can either be used as a stop watch (counting up until interrupted) or as a timer that runs for the specified amount of time. Since the sleep command is used, this script allows to specify the duration for which to count in the same precision as your sleep allows. On Debian and derivatives, this includes sub-second sleeps and a nice human-readable way to specify the time. So for example you can say:
$ time countdown 2m 4.6s
countdown 2m 4.6s 0.00s user 0.00s system 0% cpu 2:04.60 total
And as you can see, the command ran exactly for 2 minutes and 4.6 seconds without much magic in the script itself.
EDIT:
The sleepenh tool comes from the package of the same name in Debian and its derivatives like Ubuntu. For distributions that don't have it, it comes from https://github.com/nsc-deb/sleepenh
The advantage of sleepenh is, that it is able to take into account the small delay that accumulates over time from the processing of other things than the sleep during a loop. Even if one would just sleep 1 in a loop 10 times, the overall execution would take a bit more than 10 seconds because of the small overhead that comes from executing sleep and iterating the loop. This error slowly accumulates and would over time make our stopwatch timer more and more imprecise. To fix this problem, one must each loop iteration compute the precise time to sleep which is usually slightly less than a second (for one second interval timers). The sleepenh tool does this for you.
- 867
- 9
- 16
-
I don't understand what benefit this gives over my answer which also uses `sleep 0.1`. What is `sleepnh` (I can't find it in the Arch repos) and how does it differ from `sleep`? As far as I can tell, you're basically doing the same thing as my answer above. What am I missing? – terdon Jan 26 '17 at 12:28
-
@terdon Sleepenh comes from here https://github.com/nsc-deb/sleepenh The problem with just saying `sleep 5` is, that you don't sleep for exactly 5 seconds. Try for example `time sleep 5` and you see that running the command takes slightly more than 5 seconds. Over time the errors accumulate. The sleepenh utility allows to easily avoid this accumulation of error. – josch Jan 27 '17 at 08:04
-
OK. On my system I see an error of 0.002 seconds. I really doubt anyone would use this sort of tool and expect better than millisecond accuracy, but it would be better if you at least edit your answer and i) explain why `sleepnh` is better than `sleep` (you only say other answers use `sleep 1`—which they don't, only the OP uses that) and ii) where to get it and how to install it since it isn't a standard tool. – terdon Jan 27 '17 at 13:12
-
1@terdon I explained the difference between `sleep` and `sleepenh` in the first paragraph. Anyways, I probably wasn't clear enough on that so I expanded more on that at the end. The millisecond accuracy problems is what you get when calling `sleep` once. They accumulate over time and at some point it's noticable. I did not say that others only use `sleep 1`. I said that they use `sleep 1` or a busyloop. Which they still do. Show me a counter example. Answers that do `sleep 0.1` are the same as those doing `sleep 1` except that they accumulate errors even faster. – josch Jan 28 '17 at 06:49
-
I came down the answers looking for someone at least acknowledging the existence of the problem you solved. – mariotomo Feb 20 '18 at 14:11
-
I tested one of the above countdown scripts, for 300s: it took 300.674s when based on `sleep 1`, and 300.019s when based on `sleepenh`. – mariotomo Feb 20 '18 at 14:47
Take a look at TermTime. It's a nice terminal based clock and stopwatch:
pip install termtime
- 12,090
- 23
- 70
- 90
- 191
- 8
I ended up writing my own shell script: 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 visibility
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
- 12,090
- 23
- 70
- 90
- 2,641
- 2
- 14
- 13
-
1Nice script, +1. Just so you know, that is a countdown timer, not a stopwatch. – terdon Jun 25 '13 at 12:17
-
just a one liner
N=100; while [[ $((--N)) > 0 ]]; do echo $N | figlet -c && sleep 1 ; done
screenhost
Also we can clear the screen ( Terminal ) using ANSI Escape sequences using 2J format.
N=100; while [[ $((--N)) > 0 ]]; do echo -e "\033[2J\033[0m"; echo "$N" | figlet -c && sleep 1 ; done
NOTE
installing figlet command is required if you need in BIG font, otherwise remove figlet part.
N=100; while [[ $((--N)) > 0 ]]; do echo $N && sleep 1 ; done
and you can make to have a beautiful output using lolcat ...
N=100; while [[ $((--N)) > 0 ]]; do echo "$N" | figlet -c | lolcat && sleep 1 ; done
screenhsot
- 231
- 2
- 6
If your system already has Ruby, you can use:
#!/usr/bin/env ruby
n = ARGV[0].to_f
go_beginning_of_line = "\033[G"
clear_till_end_of_line = "\033[K"
time_end = Time.now + n
while Time.now < time_end
more = time_end - Time.now
print "#{go_beginning_of_line}Counting down #{more.round(1)} of #{n} seconds#{clear_till_end_of_line}"
sleep [0.1, more].min
end
puts "#{go_beginning_of_line}Counting down #{n} seconds. \a\aDone.#{clear_till_end_of_line}"
- 9,516
- 25
- 116
- 172
This is a terminal based timer: https://github.com/naa-7/terminal_work_timer
- 3,091
- 10
- 23
- 26
- 11
- 1
If you have pv installed, you can use the following one-liner to display a countdown timer and sleep for a minute (or any other amount of time, just change 60 to the desired number of seconds):
cat /dev/zero | pv -B 1 -L 1 -tpe -s 60 -S > /dev/null
You can also put it in a function:
sleep_with_progress() {
cat /dev/zero | pv -B 1 -L 1 -tpe -s "$1" -S > /dev/null
}
# If you prefer a simpler output with just the countdown:
sleep_with_countdown() {
cat /dev/zero | pv -B 1 -L 1 -e -s "$1" -S > /dev/null
}
Sample outputs taken at 5 seconds after starting:
user@host:~ $ sleep_with_progress 60
0:00:05 [===> ] 8% ETA 0:00:55
user@host:~ $ sleep_with_countdown 60
ETA 0:00:55
Explanation:
cat /dev/zero produces an infinite amount of ASCII zero (\0) characters. pv displays progress, rate limits the data flowing through it and terminates after 60 characters (details below). Finally, the redirection to /dev/null makes sure that the \0 characters are not sent to the terminal.
The parameters used for pv are:
-B 1sets the buffer size to 1.-L 1rate limits the pipe to 1 character per second.-tpeturns on the display of the time, progress and ETA indicators (while-eonly shows the latter).-s 60specifies thatpvshould expect 60 bytes.-Stellspvto stop after reaching the specified size even though the input continues (it is infinite).
- 195
- 1
- 9
Simple one liner to do the countdown job:
cnt=10;until [ $cnt -eq 0 ]; do printf "\rYour Quiz will start in $cnt seconds.... ";sleep 1;cnt=$(expr $cnt - 1);done;echo;
This one liner is taken from my open source project called Automated_Quiz, which is hosted here : https://sourceforge.net/projects/automated-quiz/
For Stopwatch :
Paste the following three lines one by one on the terminal and press enter. Press Ctrl+c on the second line to exit the stopwatch, as required.
function stopwatch() { cntd=$1; printf '%dd:%dh:%dm:%ds\n' $((cntd/86400)) $((cntd%86400/3600)) $((cntd%3600/60)) $((cntd%60)) ; };
cnt=0;while true; do printf "\rStopwatch : $cnt seconds";export var=$cnt;sleep 1;cnt=$(expr $cnt + 1);done;echo;
stopwatch $var
- 587
- 1
- 9
- 26
- 11
- 2
-
2Your answer could be improved with additional supporting information. Please [edit] to add further details, such as citations or documentation, so that others can confirm that your answer is correct. You can find more information on how to write good answers [in the help center](/help/how-to-ask). – Community Sep 13 '21 at 07:16
A Python example:
#!/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()
- 12,090
- 23
- 70
- 90
- 423
- 1
- 4
- 11
Pretend you are a person on OS X looking for a command line stopwatch. Pretend that you don't want to install the gnu tools and just want to run with the Unix date.
In that case do as terdon says, but with this 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
}
- 12,090
- 23
- 70
- 90
- 111
- 1
-
1I tried it on OS X El Capitan, for some reason it is starting with 16:00:00 – nonopolarity Oct 29 '15 at 02:34
-
ok, I found the answer. It is to use `date -ujf` instead of `date -jf` and it will begin with `00:00:00` – nonopolarity Dec 04 '20 at 18:20
Simply use watch + date in UTC time. You can also install some package for big display...
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'
Try it!
See also http://www.cyberciti.biz/faq/create-large-colorful-text-banner-on-screen/
- 353
- 1
- 4
- 17
This is similar to the accepted answer, but terdon's countdown() gave me syntax errors. This one works great for me, though:
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!"; }
You can put it in .bashrc and then execute with: timer t (where t is time in minutes).
- 12,090
- 23
- 70
- 90
- 121
- 4
Found this question earlier today, when looking for a term application to display a large countdown timer for a workshop. None of the suggestions was exactly what I needed, so I quickly put another one together in Go: https://github.com/bnaucler/cdown
As the question is already sufficiently answered, consider this to be for the sake of posterity.
- 1
- 1
$ sleep 1500 && xterm -fg yellow -g 240x80 &
When that big terminal with yellow text jumps up, time to get up and stretch!
Notes: - 1500 seconds = 25 minute pomodoro - 240x80 = terminal size with 240 character row, and 80 rows. Fills up a screen for me noticeably.
Credit: http://www.linuxquestions.org/questions/linux-newbie-8/countdown-timer-for-linux-949463/
- 251
- 2
- 4
-
But it doesn't display anything until it reaches zero. The question contained *"display a real-time countdown timer"*. – Peter Mortensen Mar 07 '20 at 18:04
A GUI version of the 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
- 125
- 4
Another option under the "existing app" category: peaclock. Displays a "large" stopwatch, timer, or clock in the terminal. Quite a few key bindings facilitate interactive use.
- 193
- 1
- 9
A slightly shorter Python (3) example:
import sys
import time
from datetime import datetime
from datetime import timedelta
start = time.time() * 1000
while True:
try:
now = time.time() * 1000
elapsed = now - start
out = str(timedelta(milliseconds=elapsed))
print(out + "\033[?25l", end='\r')
except KeyboardInterrupt:
print(out + '\033[?25h', end='\n')
sys.exit(0)
Hides / restores blinking cursor. Control-c to quit.
- 101
- 3
I'd like to suggest "timer" for a large countdown clock. It's similar to termdown but it's written in Rust and provides a nice beep at the end.
Usage
timer 11:00
timer 25min
Install
cargo install timer_core
Source: https://github.com/pando85/timer
- 123
- 5
-
-
@RohitGupta I'm not; I also found this one which I think is better: https://github.com/race604/clock-tui – robrecord Jan 27 '23 at 14:31
I added a progress bar to and unlied the variable names in terdon's answer:
countdown() {
stop="$(( $(date '+%s') + $1))"
term_width=$(tput cols)
counter_width=10
while [ $stop -ge $(date +%s) ]; do
delta="$(( $stop - $(date +%s) ))"
complete_percent=$(( 100 - ($delta * 100) / $1))
bar_width=$(($complete_percent * ($term_width - $counter_width) / 100))
printf '\r'
printf '%s ' "$(date -u -d "@$delta" +%H:%M:%S)"
printf '%0.s-' $(seq 1 $bar_width)
sleep 0.5
done
printf '\n'
}
It outputs something like:
00:00:05 --------------------
- 225
- 1
- 2
- 10
Here's a dash script (Linux/Mac OS compatible) that implements:
- An "active/pause" stopwatch
- A count up timer
- A countdown timer
#!/bin/dash
PrintInTitle () {
printf "\033]0;%s\007" "$1"
}
PrintJustInTitle () {
PrintInTitle "$1">"$print_to_screen"
}
GetSecondsSinceEpoch () {
gsse_seconds_since_epoch="$(date '+%s')"
eval $1="$gsse_seconds_since_epoch"
}
TimerStart () {
GetSecondsSinceEpoch ts_timer_seconds_since_epoch
eval ts_input_timer_seconds_since_epoch=\"\$$1\_start_time_seconds_since_epoch\"
eval ts_extra_time=\"\$$1\_extra_time_in_seconds\"
if [ ! "$ts_input_timer_seconds_since_epoch" = "-1" ]; then
if [ -z "$ts_input_timer_seconds_since_epoch" ] || [ "$ts_input_timer_seconds_since_epoch" = "0" ]; then
eval $1\_start_time_seconds_since_epoch=$ts_timer_seconds_since_epoch
eval $1\_extra_time_in_seconds="0"
else
eval $1\_start_time_seconds_since_epoch=$(( $ts_input_timer_seconds_since_epoch ))
eval $1\_extra_time_in_seconds="0"
fi
else
eval $1\_start_time_seconds_since_epoch=$(( $ts_timer_seconds_since_epoch ))
eval $1\_extra_time_in_seconds="$ts_extra_time"
fi
}
TimerGetElapsedTimeInSeconds () {
GetSecondsSinceEpoch tgetis_seconds_since_epoch
eval tgetis_input_timer_start_time_seconds_since_epoch=\"\$$1\_start_time_seconds_since_epoch\"
if [ -z "$tgetis_input_timer_start_time_seconds_since_epoch" ] || [ "$tgetis_input_timer_start_time_seconds_since_epoch" = "-1" ]; then
tgetis_input_timer_start_time_seconds_since_epoch=$(( tgetis_seconds_since_epoch ))
fi
eval tgetis_extra_time=\"\$$1\_extra_time_in_seconds\"
if [ -z "$tgetis_extra_time" ]; then
tgetis_extra_time="0"
fi
tgetis_elapsed_time_in_seconds=$(( $tgetis_seconds_since_epoch - $tgetis_input_timer_start_time_seconds_since_epoch + $tgetis_extra_time ))
eval $2=$(( $tgetis_elapsed_time_in_seconds ))
}
TimerSetTimeInSecondsSinceEpoch () {
time_to_set_in_seconds=$(( $2 ))
eval $1\_start_time_seconds_since_epoch="\"\$time_to_set_in_seconds\""
}
TimerSetTimeFullTime () {
time_to_set_full_time="$2"
GetSecondsSinceEpoch tstft_seconds_since_epoch
ConvertFullTimeToSeconds time_to_set_full_time time_to_set_in_seconds
TimerSetTimeInSecondsSinceEpoch $1 $(( $tstft_seconds_since_epoch - $time_to_set_in_seconds ))
}
TimerPause () {
TimerGetElapsedTimeInSeconds $1 tp_timer_elapsed_time_in_seconds
eval $1\_start_time_seconds_since_epoch="-1"
eval tp_timer_previous_extra_time_in_seconds=\"\$$1\_extra_time_in_seconds\"
eval $1\_extra_time_in_seconds=$(( $tp_timer_elapsed_time_in_seconds ))
}
ReGenerateFullTime () {
eval rgft_input_time=\"\$$1\"
rgft_processed_input_time=$(printf '%s' "$rgft_input_time"|sed 's/[\ \t]//g; s/D/d/g; s/H/h/g; s/M/m/g; s/S/s/g')
eval $2=\"\$rgft_processed_input_time\"
}
ConvertTimeToFullTime () {
eval cttft_input_time=\"\$$1\"
if [ "$cttft_input_time" = "0" ] || [ -z "$cttft_input_time" ]; then
cttft_full_time="0s"
else
ConvertFullTimeToSeconds cttft_input_time cttft_input_time_in_seconds
cttft_full_time=""
days=$(( $cttft_input_time_in_seconds / (24 * 60 * 60) ));
cttft_input_time_in_seconds_minus_days=$(( $cttft_input_time_in_seconds - $days * (24 * 60 * 60) ))
hours=$(( $cttft_input_time_in_seconds_minus_days / (60 * 60) ));
cttft_input_time_in_seconds_minus_days_hours=$(( $cttft_input_time_in_seconds_minus_days - $hours * (60 * 60) ))
minutes=$(( $cttft_input_time_in_seconds_minus_days_hours / (60) ));
cttft_input_time_in_seconds_minus_days_hours_minutes=$(( $cttft_input_time_in_seconds_minus_days_hours - $minutes * (60) ))
seconds=$(( $cttft_input_time_in_seconds_minus_days_hours_minutes ))
found_seconds="false"
found_minutes="false"
found_hours="false"
found_days="false"
if [ "$days" -gt "0" ]; then
days="$days""d"
found_days="true"
fi
if [ "$hours" -gt "0" ]; then
hours="$hours""h"
found_hours="true"
fi
if [ "$minutes" -gt "0" ]; then
minutes="$minutes""m"
found_minutes="true"
fi
if [ "$seconds" -gt "0" ]; then
seconds="$seconds""s"
found_seconds="true"
fi
if [ "$found_days" = "true" ]; then
cttft_full_time="$days"" "
fi
if [ "$found_hours" = "true" ]; then
cttft_full_time="$cttft_full_time$hours"" "
fi
if [ "$found_minutes" = "true" ]; then
cttft_full_time="$cttft_full_time$minutes"" "
fi
if [ "$found_seconds" = "true" ]; then
cttft_full_time="$cttft_full_time$seconds"" "
fi
cttft_full_time="${cttft_full_time%" "}"
fi
eval $2="\"\$cttft_full_time\""
}
ConvertFullTimeToSeconds () {
eval cftts_input_time_full_time="\"\$$1\""
ReGenerateFullTime cftts_input_time_full_time cftts_input_time_full_time
processed_cftts_input_time_full_time="$cftts_input_time_full_time"
if [ ! "${processed_cftts_input_time_full_time%"d"*}" = "$processed_cftts_input_time_full_time" ]; then
days="${processed_cftts_input_time_full_time%"d"*}"
while [ ! "${days}" = "${days#" "}" ]; do days="${days#" "}"; done; if [ -z "$days" ]; then days="0"; fi #Remove ' '(space)-padding from days
while [ ! "${days}" = "${days#"0"}" ]; do days="${days#"0"}"; done; if [ -z "$days" ]; then days="0"; fi #Remove '0'-padding from days
[ "$days" -eq "$days" ] 2>/dev/null||{
printf '%s' "ERROR: Invalid full time format (expected something like: 1d 2h 10m 30s). Press Enter to exit..."
read temp
exit 1
}
processed_cftts_input_time_full_time="${processed_cftts_input_time_full_time#"$days""d"}"
else
days="0"
fi
if [ ! "${processed_cftts_input_time_full_time%"h"*}" = "$processed_cftts_input_time_full_time" ]; then
hours="${processed_cftts_input_time_full_time%"h"*}"
while [ ! "${hours}" = "${hours#" "}" ]; do hours="${hours#" "}"; done; if [ -z "$hours" ]; then hours="0"; fi #Remove ' '(space)-padding from hours
while [ ! "${hours}" = "${hours#"0"}" ]; do hours="${hours#"0"}"; done; if [ -z "$hours" ]; then hours="0"; fi #Remove '0'-padding from hours
[ "$hours" -eq "$hours" ] 2>/dev/null||{
printf '%s' "ERROR: Invalid full time format (expected something like: 1d 2h 10m 30s). Press Enter to exit..."
read temp
exit 1
}
processed_cftts_input_time_full_time="${processed_cftts_input_time_full_time#"$hours""h"}"
else
hours="0"
fi
if [ ! "${processed_cftts_input_time_full_time%"m"*}" = "$processed_cftts_input_time_full_time" ]; then
minutes="${processed_cftts_input_time_full_time%"m"*}"
while [ ! "${minutes}" = "${minutes#" "}" ]; do minutes="${minutes#" "}"; done; if [ -z "$minutes" ]; then minutes="0"; fi #Remove ' '(space)-padding from minutes
while [ ! "${minutes}" = "${minutes#"0"}" ]; do minutes="${minutes#"0"}"; done; if [ -z "$minutes" ]; then minutes="0"; fi #Remove '0'-padding from minutes
[ "$minutes" -eq "$minutes" ] 2>/dev/null||{
printf '%s' "ERROR: Invalid full time format (expected something like: 1d 2h 10m 30s). Press Enter to exit..."
read temp
exit 1
}
processed_cftts_input_time_full_time="${processed_cftts_input_time_full_time#"$minutes""m"}"
else
minutes="0"
fi
seconds="${processed_cftts_input_time_full_time%"s"*}"
while [ ! "${seconds}" = "${seconds#" "}" ]; do seconds="${seconds#" "}"; done; if [ -z "$seconds" ]; then seconds="0"; fi #Remove ' '(space)-padding from seconds
while [ ! "${seconds}" = "${seconds#"0"}" ]; do seconds="${seconds#"0"}"; done; if [ -z "$seconds" ]; then seconds="0"; fi #Remove '0'-padding from seconds
[ "$seconds" -eq "$seconds" ] 2>/dev/null||{
printf '%s' "ERROR: Invalid full time format (expected something like: 1d 2h 10m 30s). Press Enter to exit..."
read temp
exit 1
}
if [ ! "${processed_cftts_input_time_full_time%"s"*}" = "$processed_cftts_input_time_full_time" ]; then
processed_cftts_input_time_full_time="${processed_cftts_input_time_full_time#"$seconds""s"}"
else
if [ -z "$processed_cftts_input_time_full_time" ]; then processed_cftts_input_time_full_time="0"; fi
seconds="$(( $processed_cftts_input_time_full_time ))"
fi
output_time_in_seconds=$(( $days * (24 * 60 * 60) + $hours * (60 * 60) + $minutes * (60) + $seconds ));
eval $2="\"\$output_time_in_seconds\""
}
trap1 () {
TimerGetElapsedTimeInSeconds t1 t1_elapsed_time_in_seconds
ConvertTimeToFullTime t1_elapsed_time_in_seconds t1_elapsed_time_full_time
TimerGetElapsedTimeInSeconds t2 t2_elapsed_time_in_seconds
ConvertTimeToFullTime t2_elapsed_time_in_seconds t2_elapsed_time_full_time
echo
echo "Exited: Elapsed time: $t1_elapsed_time_full_time | Pause time: $t2_elapsed_time_full_time"
echo
#kill all children processes, suppressing "Terminated" message:
kill -s PIPE -- -$$ 2>/dev/null
exit
}
trap2 () {
echo
echo "Exited: Elapsed time: $t1_elapsed_time_full_time / $time_to_wait"
echo
#kill all children processes, suppressing "Terminated" message:
kill -s PIPE -- -$$ 2>/dev/null
exit
}
trap3 () {
echo
echo "Exited: Remaining time: $remaining_time_full_time / $time_to_wait"
echo
#kill all children processes, suppressing "Terminated" message:
kill -s PIPE -- -$$ 2>/dev/null
exit
}
## \\// START PROGRAM HERE: \\// ##
print_to_screen='/dev/tty'
echo "Please choose an option and press Enter (default=1):"
echo " \"1\" for \"active/pause\" stopwatch"
echo " \"2\" for countup timer"
echo " \"3\" for countdown timer"
read option
if [ -z "$option" ]; then
option="1"
fi
if [ "$option" = "1" ]; then
#Trap "INTERRUPT" (CTRL-C) and "TERMINAL STOP" (CTRL-Z) signals:
trap 'trap1' INT
trap 'trap1' TSTP
#start_time="1D 23h 59M 58s"
#TimerSetTimeFullTime t1 "$start_time"
while [ "1" = "1" ]; do
TimerStart t1
TimerGetElapsedTimeInSeconds t2 t2_elapsed_time_in_seconds
ConvertTimeToFullTime t2_elapsed_time_in_seconds t2_elapsed_time_full_time
{
while [ "1" = "1" ]; do
TimerGetElapsedTimeInSeconds t1 t1_elapsed_time_in_seconds
ConvertTimeToFullTime t1_elapsed_time_in_seconds t1_elapsed_time_full_time
PrintJustInTitle "Elapsed time: $t1_elapsed_time_full_time | Pause time: $t2_elapsed_time_full_time"
sleep 0.5
done
} &
bg_PID1="$!"
printf '%s' "Press Enter to pause timer..."
read temp
kill $bg_PID1
TimerPause t1
TimerStart t2
TimerGetElapsedTimeInSeconds t1 t1_elapsed_time_in_seconds
ConvertTimeToFullTime t1_elapsed_time_in_seconds t1_elapsed_time_full_time
{
while [ "1" = "1" ]; do
TimerGetElapsedTimeInSeconds t2 t2_elapsed_time_in_seconds
ConvertTimeToFullTime t2_elapsed_time_in_seconds t2_elapsed_time_full_time
PrintJustInTitle "Elapsed time: $t1_elapsed_time_full_time | Pause time: $t2_elapsed_time_full_time"
sleep 0.5
done
} &
bg_PID2="$!"
printf '%s' "Press Enter to restart timer..."
read temp
kill "$bg_PID2"
TimerPause t2
done
elif [ "$option" = "2" ]; then
#Trap "INTERRUPT" (CTRL-C) and "TERMINAL STOP" (CTRL-Z) signals:
trap 'trap2' INT
trap 'trap2' TSTP
printf "Please provide time to wait (e.g.: 10m):"
read time_to_wait
ConvertFullTimeToSeconds time_to_wait time_to_wait_in_seconds
ConvertTimeToFullTime time_to_wait_in_seconds time_to_wait
TimerStart t1
TimerGetElapsedTimeInSeconds t1 t1_elapsed_time_in_seconds
while [ ! "$t1_elapsed_time_in_seconds" -gt "$time_to_wait_in_seconds" ]; do
TimerGetElapsedTimeInSeconds t1 t1_elapsed_time_in_seconds
ConvertTimeToFullTime t1_elapsed_time_in_seconds t1_elapsed_time_full_time
PrintJustInTitle "Elapsed time: $t1_elapsed_time_full_time / $time_to_wait"
sleep 0.5
done
echo Done.
elif [ "$option" = "3" ]; then
#Trap "INTERRUPT" (CTRL-C) and "TERMINAL STOP" (CTRL-Z) signals:
trap 'trap3' INT
trap 'trap3' TSTP
printf "Please provide time to wait (e.g.: 10m):"
read time_to_wait
ConvertFullTimeToSeconds time_to_wait time_to_wait_in_seconds
ConvertTimeToFullTime time_to_wait_in_seconds time_to_wait
TimerStart t1
TimerGetElapsedTimeInSeconds t1 t1_elapsed_time_in_seconds
remaining_time_in_seconds=$(( $time_to_wait_in_seconds - t1_elapsed_time_in_seconds ))
while [ "$remaining_time_in_seconds" -gt "0" ]; do
TimerGetElapsedTimeInSeconds t1 t1_elapsed_time_in_seconds
remaining_time_in_seconds=$(( $time_to_wait_in_seconds - t1_elapsed_time_in_seconds ))
ConvertTimeToFullTime remaining_time_in_seconds remaining_time_full_time
PrintJustInTitle "Remaining time: $remaining_time_full_time / $time_to_wait"
sleep 0.5
done
echo Done.
else
printf "Invalid option! Press Enter to exit..."
read temp;
fi
- 1
- 1
Using the top answer, I created the following version that supports any precision:
function stopwatch {
local precision="${1:-3}"
if [ "$precision" -eq 0 ]; then
start="$(gdate '+%s')"
else
start="$(gdate "+%s%${precision}N")"
fi
while true; do
if [ "$precision" -eq 0 ]; then
now="$(gdate '+%s')"
time="$((now - start))"
printf "%s\r" "$(gdate -u -d "@$time" '+%H:%M:%S')"
else
now="$(gdate "+%s%${precision}N")"
time="$((now - start))"
seconds="$((time / 10**precision))"
subseconds="$((time % 10**precision))"
printf "%s.%0${precision}d\r" "$(gdate -u -d "@$seconds" '+%H:%M:%S')" "$subseconds"
fi
done
}
- 1,108
- 2
- 12
- 17
If you would like a compilable program for whatever reason, the following would work:
#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;
}
This can be used in other programs as well and easily ported, if a Bash environment isn't available or you just prefer using a compiled program.
- 12,090
- 23
- 70
- 90
- 117
- 4





