Bash:以天、小时、分钟、秒显示秒

问题描述 投票:0回答:3

我有一个功能,灵感来自

这里
hms,但我希望扩展它以包括处理和显示天数。

我已经开始编辑脚本,但很快意识到我无法处理逻辑,时间长达数小时,反之亦然......

这是我到目前为止所拥有的:

#!/bin/bash

rendertimer(){
    # convert seconds to Days, Hours, Minutes, Seconds
    # thanks to https://www.shellscript.sh/tips/hms/
    local seconds D H M S MM D_TAG H_TAG M_TAG S_TAG
    seconds=${1:-0}
    S=$((seconds%60))
    MM=$((seconds/60)) # total number of minutes
    M=$((MM%60))
    H=$((MM/60))
    D=$((H/24))

    # set up "x day(s), x hour(s), x minute(s) and x second(s)" format
    [ "$D" -eq "1" ] && D_TAG="day" || D_TAG="days"
    [ "$H" -eq "1" ] && H_TAG="hour" || H_TAG="hours"
    [ "$M" -eq "1" ] && M_TAG="minute" || M_TAG="minutes"
    [ "$S" -eq "1" ] && S_TAG="second" || S_TAG="seconds"
    # logic for handling display
    [ "$D" -gt "0" ] && printf "%d %s " $D "${D_TAG},"
    [ "$H" -gt "0" ] && printf "%d %s " $H "${H_TAG},"
    [ "$seconds" -ge "60" ] && printf "%d %s " $M "${M_TAG} and"
    printf "%d %s\n" $S "${S_TAG}"
}

duration=${1}

howlong="$(rendertimer $duration)"
echo "That took ${howlong} to run."

所需输出

349261
秒:“运行需要 4 天 1 小时 1 分 1 秒。”

127932
秒:“运行需要 1 天 11 小时 32 分 12 秒。”

86400
秒:“运行需要 1 天。”

实际产量

349261
秒:“运行需要 4 天 97 小时 1 分 1 秒。”

127932
秒:“运行需要 1 天 35 小时 32 分 12 秒。”

86400
秒:“运行需要 1 天 24 小时 0 分 0 秒。”

有人可以帮我解决这个问题吗?

bash datetime time timer data-conversion
3个回答
2
投票

更换

H=$((MM/60))
D=$((H/24))

H=$((MM/60%24))
D=$((MM/60/24))

因此,天数是总分钟数的商,小时数是总分钟数的模数。

另外,你的第二个例子是错误的。 127932 的期望输出是

That took 1 day, 11 hours, 32 minutes and 12 seconds to run


1
投票

感谢@BeardOverflow 和@NikolaySidorov,这非常有效:

#!/bin/bash

rendertimer(){
    # convert seconds to Days, Hours, Minutes, Seconds
    # thanks to Nikolay Sidorov and https://www.shellscript.sh/tips/hms/
    local parts seconds D H M S D_TAG H_TAG M_TAG S_TAG
    seconds=${1:-0}
    # all days
    D=$((seconds / 60 / 60 / 24))
    # all hours
    H=$((seconds / 60 / 60))
    H=$((H % 24))
    # all minutes
    M=$((seconds / 60))
    M=$((M % 60))
    # all seconds
    S=$((seconds % 60))

    # set up "x day(s), x hour(s), x minute(s) and x second(s)" language
    [ "$D" -eq "1" ] && D_TAG="day" || D_TAG="days"
    [ "$H" -eq "1" ] && H_TAG="hour" || H_TAG="hours"
    [ "$M" -eq "1" ] && M_TAG="minute" || M_TAG="minutes"
    [ "$S" -eq "1" ] && S_TAG="second" || S_TAG="seconds"

    # put parts from above that exist into an array for sentence formatting
    parts=()
    [ "$D" -gt "0" ] && parts+=("$D $D_TAG")
    [ "$H" -gt "0" ] && parts+=("$H $H_TAG")
    [ "$M" -gt "0" ] && parts+=("$M $M_TAG")
    [ "$S" -gt "0" ] && parts+=("$S $S_TAG")

    # construct the sentence
    result=""
    lengthofparts=${#parts[@]}
    for (( currentpart = 0; currentpart < lengthofparts; currentpart++ )); do
        result+="${parts[$currentpart]}"
        # if current part is not the last portion of the sentence, append a comma
        [ $currentpart -ne $((lengthofparts-1)) ] && result+=", "
    done
    echo "$result"
}

duration=$1
howlong="$(rendertimer "${duration}")"
echo "That took ${howlong} to run."

0
投票

我知道这是一篇旧文章,但多一点抽象可以使它更加简洁和灵活,希望参数解析、错误处理和使用说明的示例会对某人派上用场......而且很有趣。

欢迎提出改进建议。

breakout () {
  local secs msg s unit all cnt bad times=() use="
    Use: breakout [-{a|m}] NUMBER_OF_SECONDS_1 [ [-{a|m}] NUMBER_OF_SECONDS_n..]

    Breaks NUMBER_OF_SECONDS out to time units: weeks, days, hours, minutes seconds.
    Only lists non-second units if they have nonzero values unless -a or -m was applied.

    Dash-flag options must be applied to each NUMBER_OF_SECONDS argument.
    -m  reports every time unit in the 'middle', once one has a nonzero value
    -a  reports weeks to seconds (takes precedence over -m if stacked)
  "
  (( $# )) || { echo "$use" >&2; return; }
  declare -A fill=() sxper=( [week]=604800 [day]=86400 [hour]=3600 [minute]=60 [second]=1 ) 
  for secs in "$@"
  do case $secs in
         -[am]) fill[${secs#-}]=true;                         continue ;;
      *[^0-9]*) echo "Invalid argument '$secs'" >&2; fill=(); continue ;;
     esac
     for unit in week day hour minute second
     do all=${sxper[$unit]}
        if (( secs >= all ))
        then cnt=$((secs/all)); ((cnt>1)) && s=s || s=""; msg+="${msg:+, }$cnt $unit${s:-}"; secs=$((secs%all))
        elif [[ -n "${fill[a]:-}" ]]; then msg+="${msg:+, }0 ${unit}s";
        elif [[ -n "${fill[m]:-}" ]]; then msg+="${msg:+, 0 ${unit}s}";
        fi
     done
     echo ${msg:-0 seconds}; msg=""; fill=()
  done
}

这使您可以提供具有不同格式的多个输入,并在发生错误后提供合理合理的默认值。

$: breakout

    Use: breakout [-{a|m}] NUMBER_OF_SECONDS_1 [ [-{a|m}] NUMBER_OF_SECONDS_n..]

    Breaks NUMBER_OF_SECONDS out to time units: weeks, days, hours, minutes seconds.
    Only lists non-second units if they have nonzero values unless -a or -m was applied.

    Dash-flag options must be applied to each NUMBER_OF_SECONDS argument.
    -m  reports every time unit in the 'middle', once one has a nonzero value
    -a  reports weeks to seconds (takes precedence over -m if stacked)

$: breakout 86401 -a 86401 -m 86401 -a foo -x 86401 -m 86401
1 day, 1 second
0 weeks, 1 day, 0 hours, 0 minutes, 1 second
1 day, 0 hours, 0 minutes, 1 second
Invalid argument 'foo'
Invalid argument '-x'
1 day, 1 second
1 day, 0 hours, 0 minutes, 1 second

周数可能不太有用,但很容易添加,因为它是固定的秒数。我没有费心几个月和几年,因为很少需要它们(OP 没有要求几周),并且可能不值得额外的工作来处理不同的长度。

© www.soinside.com 2019 - 2024. All rights reserved.