如何创建秒表 Bash 脚本以不断显示经过的时间?

Posted

技术标签:

【中文标题】如何创建秒表 Bash 脚本以不断显示经过的时间?【英文标题】:How do I create a stopwatch Bash script to constantly display elapsed time? 【发布时间】:2012-05-01 01:26:32 【问题描述】:

你可以把它想象成一个非常简单的秒表。我正在尝试编写一个 bash 脚本,该脚本显示自指定日期以来经过的时间并每秒更新一次输出。

首先,在脚本中指定一个 UNIX 日期:Fri Apr 14 14:00:00 EDT 2011。这将是秒表开始的时间。

现在,当您运行脚本时,您会看到...

06d:10h:37m:01s

几秒钟后你会看到......

06d:10h:37m:05s

我不想在过去的每一秒打印一个新行。该脚本应该只有 1 行输出,并且每秒更新一次。显然,您可以随时退出脚本并重新启动它,因为启动时间是硬编码的,所以它仍然会正常运行。

有什么想法吗?

【问题讨论】:

Jordanmn,我尝试通过谷歌搜索“bash stopwatch”、“bash elapsed time”和其他类似查询来修改我在网上找到的几个脚本。 【参考方案1】:

我在长时间运行的脚本中使用以下代码 sn-p。 计时器在一个函数(单独的进程)中运行,如果主进程被键盘中断终止,它将被杀死(陷阱)。输出显示从计时器开始经过的时间:

... working [hh:mm:ss]  00:07:58

sn-p:

#===  FUNCTION  ================================================================
#          NAME:  progressIndicatorTime
#   DESCRIPTION:  Display a progress indicator with seconds passed.
#    PARAMETERS:  [increment]   between 1 and 60 [sec], default is 2 [sec]
#===============================================================================
function progressIndicatorTime ()

  declare default=2                                       # default increment [sec]
  declare increment="$1:-$default"                      # 1. parameter or default
  declare format='\b\b\b\b\b\b\b\b%02d:%02d:%02d'         # time format hh:mm:ss
  declare timepassed=0
  declare seconds minutes hours

  [[ ! "$increment" =~ ^([1-9]|[1-5][0-9]|60)$ ]] && increment=$default
  printf " ... working [hh:mm:ss]  00:00:00"
  while : ; do                                            # infinite loop 
    ((seconds=timepassed%60))
    ((minutes=timepassed/60))
    ((hours=minutes/60))
    ((minutes=minutes%60))
    printf "$format" $hours $minutes $seconds
    sleep $increment || break                             # sleep ...
    ((timepassed+=increment))
  done
    # ----------  end of function progressIndicatorTime  ----------

progressIndicatorTime &                                   # run progress indicator
declare progressIndicatorPid=$!                         # save process ID
trap  "kill $progressIndicatorPid" INT TERM               # trap keyboard interrupt

#
# run long command
#

kill -s SIGTERM $progressIndicatorPid                     # terminate progress indicator

【讨论】:

【参考方案2】:

艺术可以使用一些工作,但试试这个:

#!/bin/bash

ref_date='Thu Apr 19 17:07:39 CDT 2012'
ref_sec=$(date -j -f '%a %b %d %T %Z %Y' "$ref_date" +%s)
update_inc=1

tput clear
cat <<'EOF'


            [|]     [|]
         _-'''''''''''''-_
        /                 \
       |                   |
       |                   |
       |                   |
        \                 /
         '-_____________-'
EOF

while :
do
  ((sec=$(date +%s) - $ref_sec))
  ((day=sec/86400))
  ((sec-=day*86400))
  ((hour=sec/3600))
  ((sec-=hour*3600))
  ((min=sec/60))
  ((sec-=min*60))
  tput cup 6 14
  printf "%.2id:%.2ih:%.2im:%.2is\r" $day $hour $min $sec
  sleep $update_inc
done

exit 0

请注意,第一个日期命令的语法适用于 OSX。

对于 GNU 日期,请使用 date --date="$ref_date" +%s

【讨论】:

【参考方案3】:

如果您有 Bash4 或 ksh93,则可以使用 printf %()T 语法打印 strftime 格式。以下示例是以您想要的格式打印的 Bash 4。 Bash 精度限制为 1 秒。 ksh93 支持浮点数,需要进行一些修改。

#!/usr/bin/env bash

# To supply a default date/time. To use now as the default, leave empty, or run with a null first arg.
deftime='Fri Apr 14 14:00:00 EDT 2011'

if (( $BASH_VERSINFO[0]$BASH_VERSINFO[1] >= 42 )); then
    unixTime() 
        printf $2+-v "$2" '%(%s)T' -1
    
else
    unixTime() 
        printf $2+-v "$2" "$(date '+%s')"
    
fi

stopWatch() 
    local timestamp="$(date $1:+'-d' "$1" '+%s')" curtime day=$((60*60*24)) hour=$((60**2))
    # unixTime -1 timestamp

    while
        unixTime -1 curtime
        (( curtime -= timestamp ))
        printf '%02dd:%02dh:%02dm:%02ds\r' $(( curtime / day )) $(( (curtime / hour) % 24 )) $(( (curtime / 60) % 60 )) $(( curtime % 60 ))
        do sleep 1
    done


stopWatch "$1-deftime"

您可能还对$SECONDS 变量感兴趣。不幸的是,没有方便的方法来接受您想要的人类可读的日期。这将需要大量的解析工作。 date 命令(尤其是 GNU date)可以在一定程度上做到这一点。

【讨论】:

我应该指定我在 OS X Snow Leopard 上使用 GNU bash,版本 3.2.48(1)-release (x86_64-apple-darwin10.0)。 我收到一条错误消息,显示 ./timer.sh: line 4: printf: `(': invalid format character。您知道如何修复此错误吗? 我在这里使用的功能需要 Bash 4.2。您必须将所有 printfs 替换为日期调用。我认为这就像更改 unixTime 函数一样简单......我必须对其进行测试 好吧,现在应该可以在 Bashes 3.1 及更高版本中使用。在这里拥有 4.2 的唯一好处是节省了一个子shell。 哇!!很酷!!但是你是说它不能有固定的开始日期吗?现在的情况是,如果我关闭 shell,它会重新开始。

以上是关于如何创建秒表 Bash 脚本以不断显示经过的时间?的主要内容,如果未能解决你的问题,请参考以下文章

秒表或计时器

无法使用pyqt5显示秒表

BackgroundWorker使用秒表更新经过的时间标签,由于调用C#而冻结[重复]

do 循环的 Bash 脚本,用于检测经过的时间段然后继续

使用JavaScript通过一定时间后运行函数?

秒表的使用方法 秒表有几种计时方式