有没有办法在终端中显示倒计时或秒表计时器?


144

如何在Linux终端上显示实时倒数计时器?是否有一个现有的应用程序,或者甚至更好的一个班轮来做到这一点?

Answers:


184

我不确定您为什么需要它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
}

请注意,该stopwatch功能尚未经过几天的测试,因为我真的不想等待24小时。它应该可以,但是如果不能,请告诉我。


9
.zshrc阅读您的答案后,我在右侧添加了这些不错的功能。今天,我countdown第一次使用它,发现CPU使用率很高。我添加了一个sleep 0.1(我不知道所有系统是否都支持小数秒的睡眠时间),这改善了很多。缺点当然是显示精度不高,但是我可以承受最大偏差。100毫秒
mpy

@mpy感谢您提及。在执行此操作时bash,我获得了约3%的CPU使用率,我可以忍受(尽管它比我预期的高,而且我也将睡眠添加到了自己的.bashrc中)。
terdon

3
刚找到这个答案。我发现将回车符放在秒表函数的echo语句的开头很方便,因为这意味着杀死秒表不会覆盖当前的秒表时间:echo -ne“ \ r $(date -u --date @ $ ((date +%s-$ date1))+%H:%M:%S)“;
mkingston 2014年

3
@chishaku:在OS X上,这似乎对我有用: echo -ne "$(date -ju -f %s $(($date1 - date +%s )) +%H:%M:%S)\r";
user1071847'7

1
随着SOX包我想补充一个漂亮的声音在倒计时结束播放:play -q -n synth 2 pluck C5
Pablo A

94

我最喜欢的方式是:

开始:

time cat

停止:

ctrl+c

就像@wjandrea在下面评论的那样,另一个版本要运行:

time read

然后按Enter停止



8
类似,但您可以按Enter键将其停止:time read
wjandrea

10
time read在zsh中失败,但是time (read)可以工作。
Sparhawk

但问题是,您必须取消或完成时间才能看到时间。当您重新启动它时,计时器重新开始。
Zelphir Kaltstahl,

38

我一直在寻找相同的东西,最终用Python编写了一些更精致的东西:

这将为您提供10秒的简单倒计时:

sudo pip install termdown
termdown 10

资料来源:https : //github.com/trehn/termdown


1
@DoktoroReichard:好吧,这是一个下载链接。
harrymc 2014年

1
@Suhaib:应该而且应该为我做。请在GitHub上提出问题,以获取更多信息。
trehn 2014年

1
我喜欢它-这是我熟悉的
韦恩沃纳

1
非常好,我喜欢ASCII
Guillermo

1
这真是太酷了!😄
orschiro

13

我已经使用了这个:

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"

这是消息来源


2
兼容
POSIX-

13
sh-3.2# man leave

设置计时器15分钟

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

编辑:我打开了一堆链接,我认为这是特定于osx,对此感到抱歉。留下我的答案,以便其他人意识到BSD的休假。


1
离开也可以在Linux中使用,但是首先您必须从默认存储库中安装离开程序。
karel 2016年

6

这是秒表的百分之一秒:

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


不错的纯Linux解决方案!我喜欢没有外部电话。注意,我的Debian系统在/ proc / uptime中有两个值,第二个大概是指我以前的正常运行时间。可以对此脚本进行调整,以通过将第5行更改为return $1
Adam Katz

4

我将很好的terdon答案组合到了功能中,该功能同时显示从开始到结束的时间。还有三个变体,因此更容易调用(不必进行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中的代码

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( 在babun / win7中对我有用)中播放声音的某种方式结合起来,您将获得一个简单而灵活的带有警报的计时器cat /path/foo.wav > /dev/dsp


4

另一种方法

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

对于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显然更好。


3

我最终写了自己的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 

1
不错的脚本,+ 1。请注意,这是一个倒数计时器,而不是秒表。
terdon 2013年

哈,你说得对,那就是我真正想要的。我将更新命名。
tir38

3

我很惊讶没有人sleepenh在脚本中使用该工具。取而代之的是,提出的解决方案要么sleep 1在后续的定时器输出之间使用a ,要么使用一个尽快输出的繁忙循环。前者是不足够的,因为由于花了很少的时间进行打印,所以输出实际上不会每秒发生一次,但会比次优输出少一点。经过足够的时间后,计数器将跳过一秒钟。后者是不够的,因为它没有充分的理由使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工具为您完成此任务。


我不明白这给我的答案带来了什么好处sleep 0.1。什么是什么sleepnh(我在Arch仓库中找不到),它和它有什么不同sleep?据我所知,您基本上在做与我上面的回答相同的事情。我想念什么?
terdon

@terdon Sleepenh来自这里github.com/nsc-deb/sleepenh刚才说的问题sleep 5是,您恰好没有睡5秒钟。以尝试为例time sleep 5,您发现运行命令花费的时间略超过5秒。随着时间的流逝,错误会累积。sleepenh实用程序可轻松避免这种错误累积。
josch

好。在我的系统上,我看到0.002秒的错误。我真的怀疑有人会使用这种工具并期望比毫秒精度更好,但是如果您至少编辑答案,那会更好(我)解释为什么sleepnh要比sleep(您只说其他答案有用sleep 1-他们没有这样做)更好,只有OP会使用它,并且ii)由于它不是标准工具,因此在何处获取它以及如何安装它。
terdon

1
@terdon我在第一段中解释了sleep和之间的区别sleepenh。无论如何,我可能对此还不够清楚,所以最后我做了更多的扩展。毫秒精度问题是您调用sleep一次时遇到的问题。他们随着时间的推移而积累,在某些时候值得注意。我不是说别人只用sleep 1。我说他们用sleep 1还是忙循环。他们仍然这样做。给我看一个反例。答案与答案sleep 0.1相同,sleep 1只是答案会更快地累积错误。
josch

我从答案中寻找至少有人承认您解决了问题的人。
mariotomo

2

简短答案:

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

说明:

我知道有很多答案,但是我只想发布一些与OP问题非常接近的内容,我个人认为确实是“ 终端中的oneliner倒计时 ”。我的目标是:

  1. 一支班轮。
  2. 倒数。
  3. 易于记忆和在控制台中键入(没有功能和繁琐的逻辑,仅适用于bash)。
  4. 不需要安装其他软件(即使我在那里没有root用户,也可以在通过ssh访问的任何服务器上使用)。

这个怎么运作:

  1. seq 打印从60到1的数字。
  2. echo -ne "\r$i "将插入号返回到字符串的开头并显示当前$i值。如果前一个值的字符长度比当前值长$i(10-> 9),则必须覆盖该后一个空格。

1
这对于在Mac OS上用于bash脚本的用例来说效果最好。有关其工作原理的说明特别有用。
詹姆斯·坎贝尔


1

假设您是OSX上正在寻找命令行秒表的人。假设您不想安装gnu工具,而只想与unix一起运行date

在这种情况下,请按照@terdon的说明进行操作,但要进行以下修改:

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
我在OS X El Capitan上进行了尝试,出于某种原因,它以16:00:00开始
nopole 2015年

1

只需在UTC时间中使用watch + date。您还可以安装一些用于大型显示​​的软件包...

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/


1

sw是一款可以永久运行的简单秒表。

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

1

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

演示


1

看看TermTime,这是一个不错的基于终端的时钟和秒表:

pip install termtime


0

这类似于已接受的答案,但是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是时间,以分钟为单位)。


0

今天早些时候,在寻找一个用于显示车间大倒数计时器的术语应用程序时,发现了这个问题。这些建议都不是我真正需要的,因此我很快就在Go中提出了另一个建议:https : //github.com/bnaucler/cdown

由于已经充分回答了这个问题,因此认为这是后代的缘故。



0

秒表的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

-2

如果您出于任何原因想要一个可编译程序,则可以使用以下程序:

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

如果无法使用bash环境,或者您只喜欢使用已编译的程序,则也可以在其他程序中使用它,并且可以轻松移植

的github

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.