如何在bash中将sleep格式的时间段字符串转换为秒

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

这是关于常见linux命令接受的格式的时间字符串

sleep
, 比如“3d 7h 5m 10s”(3天7小时5分10秒), 这将导致:

(3 * 24 * 60 * 60) + (7 * 60 * 60) + (5 * 60) + 10 = 284710

请注意,这 4 个元素并非全部都必须存在,且顺序也不正确, 并且一个元素可能会出现多次。 所以“3s 5s 6h”也是有效的,并且应该导致:

(6 * 60 * 60) + (3 + 5) = 21608

bash parsing time
5个回答
4
投票

当您用相应的因子替换字母时,您可以将其通过管道传输到

bc
。您只需要处理该行末尾的
+
即可。

t2s() {
   sed 's/d/*24*3600 +/g; s/h/*3600 +/g; s/m/*60 +/g; s/s/\+/g; s/+[ ]*$//g' <<< "$1" | bc
}

试运行

$ t2s "3d 7h 5m 10s"
284710
$ t2s "3d 7h 5m "
284700
$ t2s "3s 5s 6h"
21608

1
投票

我不知道是否有适合您要求的预定义命令,但我使用 GNU

grep
paste
bc
想出了一个更紧凑且无循环的脚本。

使用示例,假设脚本保存为

t2sec
:

  • t2sec 3s
    打印
    3
  • t2sec "2m 1s"
    t2sec "1s 2m"
    t2sec "1m 1s 1m"
    全部打印
    121
  • t2sec "1s 2s"
    t2sec "1s2s"
    t2sec 1s 2s
    t2sec "  1s 2s "
    全部打印
    3
  • t2sec
    t2sec ""
    t2sec "1x"
    t2sec "s"
    均不打印任何内容并以状态 1 退出。
#! /bin/bash  

t="$*"

# validate
grep -Pqx '( *\d+[smhd])+ *' <<< "$t" || exit 1

# helper functions
sumAndMultiply() { bc <<< "(0$(paste -s -d+))*$1"; }
xToSeconds() { grep -Po "\\d+(?=$1)" | sumAndMultiply "$2"; }

# convert to seconds
(
        xToSeconds s 1 <<< "$t";
        xToSeconds m 60 <<< "$t";
        xToSeconds h 3600 <<< "$t";
        xToSeconds d 86400 <<< "$t";
) | sumAndMultiply 1

1
投票

基于 bash 函数的解决方案,支持天、小时、分钟和秒。

文件

sleepTimeToSeconds

#!/bin/bash

# Converts a time string like "2h 3m 3s" to the amount of seconds
function timeToSeconds() {
    timeStr="$@"

    # validate
    grep -Pqx '( *\d+[smhd] +)+' <<< "$timeStr "
    if [ $? != 0 ]
    then
        >&2 echo "error: Bad time format"
        exit 1
    fi

    secs=0
    for timePart in $timeStr
    do
        timeType=${timePart//[[:digit:]]/}
        timeAmount=${timePart//[[:alpha:]]/}

        toSecsFactor=0
        case "$timeType" in
            s|'')
                toSecsFactor=1
                ;;
            m)
                toSecsFactor=60
                ;;
            h)
                let toSecsFactor="60 * 60"
                ;;
            d)
                let toSecsFactor="60 * 60 * 24"
                ;;
            *)
                >&2 echo "Bad time string type: '$timeType'"
                exit 2
                ;;
        esac
        let secs="$secs + ( $timeAmount * $toSecsFactor )"
    done

    echo -n $secs
}

timeToSeconds "$@"

测试:

> sleepTimeToSeconds "5s 4s 1d 2h 3m"
93789

1
投票

在极少数情况下,您没有

bc
可用: (也许像我一样遭受 bash-on-Windows 的困扰?)

然后@WalterA函数

t2s
可以改成这样:

t2s() {
   eq=$(sed 's/d/*24*3600 +/g; s/h/*3600 +/g; s/m/*60 +/g; s/s/\+/g; s/+[ ]*$//g' <<< "$1")
   ((val=eq))
   echo "$val"
}

0
投票

关于这个问题的Walter A 答案可以得到加强。

为了与 Mac OS 和其他平台兼容,最好为 sed 启用 ERE 模式(-E 标志)。启用 ERE 后,我们应该始终在规则的正则表达式部分中转义加号(请参阅此处)。另外,我们不需要在规则的替换部分中转义加号。

所以,这是固定的

t2s
bash 函数:

t2s() {
   sed -E 's/d/*24*3600 +/g; s/h/*3600 +/g; s/m/*60 +/g; s/s/+/g; s/\+[ ]*$//g' <<< "$1" | bc
}

测试:

$ t2s "60m"
3600
$ t2s "1h50m50s"
6650
© www.soinside.com 2019 - 2024. All rights reserved.