我不知道你为什么需要beep
,如果你想要的只是一个秒表,你可以这样做。
while true; do echo -ne "`date`\r"; done
这样就能显示出实时的秒数,你可以用Ctrl+C停止它。如果你需要更高的精度,你可以用这个来给你纳秒。
while true; do echo -ne "`date +%H:%M:%S:%N`\r"; done
最后,如果你真的,真的想要 “秒表格式",一切从0开始,然后开始增长,你可以这样做:
date1=`date +%s`; while true; do
echo -ne "$(date -u --date @$((`date +%s` - $date1)) +%H:%M:%S)\r";
done
对于一个倒计时的计时器(这不是你最初的问题所要求的),你可以这样做(相应地改变秒数):
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
你可以通过使用bash(或者任何你喜欢的shell)函数将这些命令组合成简单的命令。在bash中,将这些行添加到你的~/.bashrc
中(sleep 0.1
会让系统在每次运行之间等待1/10秒,这样你就不会浪费你的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
}
然后你可以通过运行:
countdown 60
来启动一分钟的倒计时器。
countdown $((2*60*60))
或者使用以下命令进行一整天的倒计时:
countdown $((24*60*60))
。
stopwatch
启动秒表:
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
}
如果你需要能够处理天以及小时、分钟和秒,你可以这样做。
0x1&
_注意,stopwatch
功能还没有测试过几天,因为我真的不想等24小时。它应该能用,但如果不能用,请告诉我。
我用过这个。
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
)
例子:
countdown "00:07:55"
这里有一个源。
这是以百分之一秒为单位的秒表:
#!/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
}
}
示例 。
简答。
for i in `seq 60 -1 1` ; do echo -ne "\r$i " ; sleep 1 ; done
解释:
我知道有很多答案,但我只想贴出与OP的问题非常接近的东西,我个人认为确实是 “终端的单行线倒计时"。我的目标是
1 一句话: 2. 2.倒计时。 3. 易于记忆和在控制台中打字(没有函数和重逻辑,只有bash)。 4. 不需要安装额外的软件(可以在我通过ssh去的任何服务器上使用,即使我在那里没有root)。
工作原理。
seq
打印从60到1的数字 echo -ne "\r$i "
返回到字符串的开头并打印当前的$i
值。后面的空格是用来覆盖之前的值,如果它比当前的$i
长一个字符(10 -> 9)。我结合了非常好的 terdon 的答案,将其转化为同时显示从开始到结束的时间的函数,也有三个变体,所以更容易调用 (你不必做 bash 数学运算),而且它也是抽象的。也有三个变体,所以更容易调用(你不必做bash数学),而且它也是抽象的。使用实例 。
{ ~ } » 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
还有一些类似工作计时器的东西:
{ ~ } » 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
如果你需要一些非常具体的时间:
{ ~ } » 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
这里是代码,可以放到你的.Bashrc中。 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]}))
}
把它和一些在linux终端中播放声音的方法结合起来通过Linux命令行播放mp3或wav文件)或cygwin(cat /path/foo.wav > /dev/dsp
在babun/win7中为我工作),你就有了一个简单灵活的带闹钟的定时器!
我最后写了我自己的shell脚本。github gist
#!/bin/sh
# script to create timer in terminal
# Jason Atwood
# 2013/6/22
# start up
echo "starting timer script ..."
sleep 1 # seconds
# get input from user
read -p "Timer for how many minutes?" -e DURATION
DURATION=$(( $DURATION*60 )) # convert minutes to seconds
# get start time
START=$(date +%s)
# infinite loop
while [-1]; do
clear # clear window
# do math
NOW=$(date +%s) # get time now in seconds
DIF=$(( $NOW-$START )) # compute diff in seconds
ELAPSE=$(( $DURATION-$DIF )) # compute elapsed time in seconds
MINS=$(( $ELAPSE/60 )) # convert to minutes... (dumps remainder from division)
SECS=$(( $ELAPSE - ($MINS*60) )) # ... and seconds
# conditional
if [$MINS == 0] && [$SECS == 0] # if mins = 0 and secs = 0 (i.e. if time expired)
then # blink screen
for i in `seq 1 180`; # for i = 1:180 (i.e. 180 seconds)
do
clear # flash on
setterm -term linux -back red -fore white # use setterm to change background color
echo "00:00 " # extra tabs for visibiltiy
sleep 0.5
clear # flash off
setterm -term linux -default # clear setterm changes from above
echo "00:00" # (i.e. go back to white text on black background)
sleep 0.5
done # end for loop
break # end script
else # else, time is not expired
echo "$MINS:$SECS" # display time
sleep 1 # sleep 1 second
fi # end if
done # end while loop
```。
我很惊讶,没有人在他们的脚本中使用sleepenh
工具。相反,提出的解决方案要么在后续的定时器输出之间使用sleep 1
,要么使用一个尽可能快的输出的忙循环。前者是不够的,因为由于做打印的时间很小,实际上不会每秒输出一次,而是少了一点,这是次优的。时间过够后,计数器会跳过一秒。后者是不够的,因为它会让CPU无端忙碌。
我的$PATH
里的工具是这样的。
#!/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
这个脚本既可以作为一个停表(一直到中断为止),也可以作为一个定时器,在指定时间内运行。由于使用了 sleep
命令,这个脚本允许指定持续时间,其精度与 sleep
允许的一样。在Debian和衍生产品上,这包括亚秒级的睡眠和一个很好的人类可读的方式来指定时间。例如,您可以说
$ time countdown 2m 4.6s
countdown 2m 4.6s 0.00s user 0.00s system 0% cpu 2:04.60 total
正如你所看到的,这个命令精确地运行了2分4. 6秒,脚本本身并没有太多魔法。
编辑 。
sleepenh工具来自Debian及其衍生版本(如Ubuntu)的同名软件包。对于没有这个工具的发行版,它来自 https://github.com/nsc-deb/sleepenh
sleepenh的优势在于,它能够考虑到循环过程中除了睡眠之外的其他事情处理所累积的小延迟。即使只是在循环中sleep 1
10次,由于执行sleep
和循环迭代带来的小开销,整体执行时间会超过10秒。这个错误会慢慢积累,随着时间的推移,会让我们的秒表计时器越来越不精确。为了解决这个问题,必须每次循环迭代都要计算出精确的睡眠时间,这个时间通常略小于一秒(对于一秒区间定时器)。sleepenh工具可以帮你完成这个任务。
另一种方法
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
如果想在零点时得到一个信号,可以用一个在零点时返回非零退出状态的命令来建立,然后结合watch -b
之类的,但如果想建立一个更复杂的脚本,这可能不是办法;它更像是一个 “快速而肮脏的单行本 "类型的解决方案。
我总体上喜欢watch
这个程序。我第一次看到它,是在我已经写了无数个while sleep 5; do
循环到不同效果之后。watch
是明显的比较好的。
sw 是一个简单的秒表,它将永远运行。
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
只需使用手表+日期的UTC时间。你也可以安装一些大显示屏的软件包……
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'
试试吧!
参见 http://www.cyberciti.biz/faq/create-large-colorful-text-banner-on-screen/ 。
一个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()
GUI版本的秒表
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
```。
今天早些时候,当我在寻找一个术语应用程序来显示一个大型的倒计时计时器时,发现了这个问题。所有的建议都不是我所需要的,所以我很快就在Go中又做了一个。https://github.com/bnaucler/cdown
由于这个问题已经得到了充分的回答,所以为了方便后人,就把它放在这里吧。
$ sleep 1500 && xterm -fg yellow -g 240x80 &
当那个带着黄色文字的大终端跳起来的时候,是时候站起来伸个懒腰了!
备注。- 1500秒 = 25分钟pomodoro - 240x80 = 终端大小,240个字符行,80行。对我来说,填满一个屏幕很明显。
信用: http://www.linuxquestions.org/questions/linux-newbie-8/countdown-timer-for-linux-949463/ 。
这和公认的答案类似,但是 terdon 的 countdown()
给我带来了语法错误。不过这个对我来说很好用:
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
里,然后用: timer t
(其中t是时间,以分钟为单位)。
如果你出于任何原因想要一个可编译的程序,下面的方法就可以了。
#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;
}
这也可以用在其他程序中,而且很容易移植,如果bash环境不可用,或者你只是喜欢用编译过的程序 github 。