我正在尝试将描述时间间隔的字符串转换为相应的秒数。
经过一些实验,我发现我可以这样使用date
:
soon=$(date -d '5 minutes 10 seconds' +%s); now=$(date +%s)
echo $(( $soon-$now ))
,但我认为应该有一个更简单的方法来转换字符串,如"5分钟10秒"到相应的秒数,在这个例子310。是否有办法在一个命令中做到这一点?
注意:虽然可移植性很有用,但它不是我的首要任务。
可以从epoch
开始date -d"1970-01-01 00:00:00 UTC 5 minutes 10 seconds" "+%s"
310
你也可以很容易地把times
Time="1 day"
date -d"1970-01-01 00:00:00 UTC $Time" "+%s"
86400
有一种方法可以做到这一点,在纯bash
中不使用date
命令(为了可移植性)
假设您只有一个输入字符串来转换bash
变量中的"5分钟10秒",:
分隔符如下所示。
$ convertString="00:05:10"
$ IFS=: read -r hour minute second <<< "$convertString"
$ secondsValue=$(((hour * 60 + minute) * 60 + second))
$ printf "%sn" "$secondsValue"
310
您可以直接在命令行上运行上述命令,而不需要使用$
标记。
这样做(添加epoch 19700101):
$ date -ud '19700101 5 minutes 10 seconds' +%s
310
添加-u
以避免本地时间(和夏令时)影响是很重要的。
$ TZ=America/Los_Angeles date -d '19700101 5 minutes 10 seconds' +%s
29110
注意date可以做一些数学运算:
$ date -ud '19700101 +5 minutes 10 seconds -47 seconds -1 min' +%s
203
前面的建议在alpine linux上不能正常工作,所以这里有一个小的辅助函数,它是POSIX兼容的,易于使用,还支持计算(只是作为实现的副作用)。
函数总是根据所提供的形参返回一个整数。
$ durationToSeconds '<value>' '<fallback>'
$ durationToSeconds "1h 30m"
5400
$ durationToSeconds "$someemptyvar" 1h
3600
$ durationToSeconds "$someemptyvar" "1h 30m"
5400
# Calculations also work
$ durationToSeconds "1h * 3"
10800
$ durationToSeconds "1h - 1h"
0
# And also supports long forms for year, day, hour, minute, second
$ durationToSeconds "3 days 1 hour"
262800
# It's also case insensitive
$ durationToSeconds "3 Days"
259200
function durationToSeconds () {
set -f
normalize () { echo $1 | tr '[:upper:]' '[:lower:]' | tr -d ""\'" | sed 's/years{0,1}/y/g; s/months{0,1}/m/g; s/days{0,1}/d/g; s/hours{0,1}/h/g; s/minutes{0,1}/m/g; s/min/m/g; s/seconds{0,1}/s/g; s/sec/s/g; s/ //g;'; }
local value=$(normalize "$1")
local fallback=$(normalize "$2")
echo $value | grep -v '^[-+*/0-9ydhms]{0,30}$' > /dev/null 2>&1
if [ $? -eq 0 ]
then
>&2 echo Invalid duration pattern "$value"
else
if [ "$value" = "" ]; then
[ "$fallback" != "" ] && durationToSeconds "$fallback"
else
sedtmpl () { echo "s/([0-9]+)$1/(01 * $2)/g;"; }
local template="$(sedtmpl '( |$)' 1) $(sedtmpl y '365 * 86400') $(sedtmpl d 86400) $(sedtmpl h 3600) $(sedtmpl m 60) $(sedtmpl s 1) s/) *(/) + (/g;"
echo $value | sed "$template" | bc
fi
fi
set +f
}
编辑:是。我在评论后为OP开发了,并在Mac OS X, CentOS和Ubuntu上进行了检查。一个线性的POSIX兼容命令,用于将"X分钟Y秒"格式转换为秒。这就是问题所在。
echo $(($(echo "5 minutes 10 seconds" | cut -c1-2)*60 + $(echo "5 minutes 10 seconds" | cut -c1-12 | awk '{print substr($0,11)}')))
OP通过评论告诉我,他想要"X分Y秒"格式,而不是HH:MM:SS
格式。带有date
和"+%s"
的命令在(我的)Mac上抛出错误。OP想要从"X分钟Y秒"格式中获取数值并将其转换为秒。首先,我以数字形式提取分钟(将其作为方程A):
echo "5 minutes 10 seconds" | cut -c1-2)
然后我提取第二部分(把它作为方程B):
echo "5 minutes 10 seconds" | cut -c1-12 | awk '{print substr($0,11)}'
现在将分钟乘以60,然后与另一个相加:
echo $((equation A)*60) + (equation B))
OP应该要求其他人检查我的开发版本(但工作)命令,然后再使用它进行自动重复使用,就像我们在生产服务器上使用cron一样。
如果我们想在一个日志文件上运行它,它的值是"X分钟Y秒"格式,我们必须将echo "5 minutes 10 seconds"
更改为cat file | ...
类似的命令。我也保留了它的要点,如果我或其他人需要,我们可以使用它与cat
运行在服务器日志文件与x minutes y seconds
类似的日志格式。
虽然离题(我所理解的,问题与当前时间没有太大关系),但这不适用于posix兼容的操作系统以秒为单位获取当前时间:
date -d "1970-01-01 00:00:00 UTC 5 minutes 10 seconds" "+%s"
它会在MacOS X上抛出错误,但在大多数GNU/Linux发行版上都可以工作。+%s
部分在posix兼容的操作系统上复杂使用时会抛出错误。这些命令主要适用于在POSIX兼容的任何类型的unix(如OS)上以秒为单位获取当前时间:
awk 'BEGIN{srand(); print srand()}'
perl -le 'print time'
如果OP需要,可以通过生成以秒为单位的当前时间并减去来扩展它。我希望它会有所帮助。
----编辑前的旧答案----
你可以得到当前的时间没有date
—echo | awk '{print systime();}'
或wget -qO- http://www.timeapi.org/utc/now?\s
。另一种将时间转换为秒的方法是echo "00:20:40.25" | awk -F: '{ print ($1 * 3600) + ($2 * 60) + $3 }'
。
在另一个答案中显示的printf
的示例近乎完美。
你想要的东西总是GNU/Linux的基本实用程序所需要的- gnu.org/../../../../../Setting-an-Alarm.html
接近的方式真的取决于你需要多少万无一失的方式。