麻烦的mac date命令

时间:2014-11-08 07:52:33

标签: macos shell date terminal

我目前遇到了mac date command的两个问题。

我正在运行一个shell脚本,该脚本首先执行命令(ps -p $ p_id -o etime =),以使用 p_id 为我提供进程的已用时间,返回 [[dd-] hh:] mm:ss

形式的日期

问题1:以下命令将日期转换为另一种格式似乎导致了奇怪的问题: (日期-j -f“%H:%M:%s”“$ processStartTime”“+%H:%M:%s”)。 说 prcoessStartTime = 12:30:33 。此命令返回的输出日期为 01:00:33 ,即使我将日期转换为相同的格式。它只能得到正确的秒数,小时和分钟是错误的。如果我使用不同的引号,如''围绕日期格式,我甚至得到更奇怪的结果!目标是将时间转换为分钟,以便我可以看到该过程运行了多少分钟。

问题2:由于处理日期可以采用以下格式 [[dd-] hh:] mm:ss 我应该如何在代码中处理不同的日期格式?我应该有3个条件来检查格式吗?还是有办法处理这个?即一些日期可能是hh:mm:ss和其他mm:ss的形式,我需要在命令中输入日期格式正确,否则会引发错误。

3 个答案:

答案 0 :(得分:1)

字符串操作的两种不同方式

使用sed格式化MaxOS的日期 dst 格式。

有一个强大的sed命令来重置MacOs的日期命令的值(不是很性感,但它有效):

date -j $(
  ps ho lstart= $p_id |
    sed '
      s/^....//;
      s/Jan/01/;s/Feb/02/;s/Mar/03/;s/Apr/04/;s/May/05/;s/Jun/06/;
      s/Jul/07/;s/Aug/08/;s/Sep/09/;s/Oct/10/;s/Nov/11/;s/Dec/12/;
      s/^\([0-9]\{2\}\) \([0-9]\{2\}\) \([0-9]\{2\}\):\([0-9]\{2\}\):\([0-9]\{2\}\) [0-9]\{2\}\([0-9]\{2\}\)/\1\2\3\4\6.\5/;
            ') +%s

这将在 unixtimestamp 中呈现进程$p_id的开始时间。

使用解析日期值

# Building translation variables for months strings
for ((i=1;i<13;i++));do
    val=$(printf %02d $i)
    mnt=$(date -j ${val}010101 +%b)
    eval mn$mnt=$val
  done

IFS=': ' read -a psdate < <(ps ho lstart= $p_id)
var=mn${psdate[1]}
printf -v fdte "%02d%02d%02d%02d%02d.%02d" ${!var} ${psdate[2]} \
     ${psdate[3]} ${psdate[4]} ${psdate[6]#??} ${psdate[5]}
date -j $fdte +%s

这两个命令都在MacOS上测试过。我发现第二个性感

答案 1 :(得分:0)

你似乎在搅拌苹果和橘子。

date命令与时间戳一起使用 - 这些是单个离散时间点的简单原子表示,因此,它们指的是绝对时间。在实现方面,time_t传统上是UTC时间1970年1月1日午夜(在Unix上)的秒数。

相比之下,您正在处理的时间信息是 relative ,表示时间范围

如果A是&#34;现在&#34; &B是&#34;一小时三十三秒&#34;,它是指从A-B开始到A结束的时间,还是指从A开始到A + B结束的时间?或者它与其他一些时间点相关? date命令通常解释没有相对于前一个午夜的日期的时间;所以你(隐含地)得到一个从午夜开始并在指定时间结束的范围。

date命令还有一个解析器,用于表示相对时间的各种人类表达,但它必然是不准确和不可预测的,因为它是人类语言的方式。

vbvntv$ date -d 'tomorrow 07:00'
Tue Nov 11 07:00:00 EET 2014

我无法访问可以对其进行测试的Mac,但通常情况下,在解析人类日期时似乎功能较差且功能较差。

在您的情况下,您不清楚自己真正想做什么。也许你想计算A-B的时间,即给定现在完成的工作量(A)并花费B时间,何时开始?

这样做的常用方法是将它们转换为绝对秒数。

vbvntv$ date -d "00:00" 
Mon Nov 10 00:00:00 EET 2014

vbvntv$ date -d "00:00" +%s 
1415570400

vbvntv$ date -d "01:00:33" 
Mon Nov 10 01:00:33 EET 2014

vbvntv$ date -d "01:00:33" +%s
1415574033

vbvntv$ echo $((1415574033-1415570400))
3633

vbvntv$ date -d "3633 seconds ago"
Mon Nov 10 09:53:05 EET 2014

vbvntv$ # or alternatively

vbvntv$ date +%s
1415609708

vnvntv$ date -d @$((1415609708-3633))
Mon Nov 10 09:53:15 EET 2014

答案 2 :(得分:0)

解决问题没有。 1 您必须将%s替换为%S(正如RBH已经建议的那样):

processStartTime='12:30:33'
- date -j -f "%H:%M:%s" "$processStartTime" "+%H:%M:%s"
+ date -j -f "%H:%M:%S" "$processStartTime" "+%H:%M:%S"

结合F. Hauri引入的ps ho lstart= $pid方法与设置LANG='C',可以避免问题没有。 2 ::

{
pid='1'
ps_date="$(LANG='C' ps ho lstart= $pid)"
# convert ps_date to Unix epoch time
processStartTimeEpochTime="$(LANG='C' date -j -f '%a %b %d %T %Y' "$ps_date" '+%s' 2>/dev/null)"
elapsed_secs="$(( $(date '+%s') - ${processStartTimeEpochTime} ))"
printf '%s\n' "ps_date: $ps_date" "processStartTimeEpochTime: $processStartTimeEpochTime"
printf '%s\n' "elapsed seconds: $elapsed_secs" "elapsed minutes: $(( $elapsed_secs / 60 ))" "elapsed hours: $(( $elapsed_secs / 3600 ))"
printf '%s' 'processStartTimeEpochTime reversed: '
date -r "$processStartTimeEpochTime" '+%F--%T'
}

如果您坚持使用 ps -p $pid -o etime= ,由于解析了 [[dd-]hh:]mm:ss 格式,它会变得有点笨拙。

{

pid='1'

# days, hours, minutes, seconds
# format: [[dd-]hh:]mm:ss
dhms="$(ps -p $pid -o etime=)"

days=""
h=""
m=""
s=""

get_hms() {
   hms="$1"
   h=${hms%%:*}
   hms=${hms#*:};
   m=${hms%%:*}
   hms=${hms#*:};
   s=${hms}
   return 0
}

case "$dhms" in
   ??-??:??:??) days=${dhms%%-*}; hms=${dhms#*-}; get_hms "$hms";;
   ?-??:??:??) days=${dhms%%-*}; hms=${dhms#*-}; get_hms "$hms";;
   ??:??:??) days="0"; hms="$dhms"; get_hms "$hms";;
   ?:??:??) days="0"; hms="0${dhms}"; get_hms "$hms";;
   ??:??) days="0"; hms="00:${dhms}"; get_hms "$hms";;
   ?:??) days="0"; hms="00:0${dhms}"; get_hms "$hms";;
   ??) days="0"; hms="00:00:${dhms}"; get_hms "$hms";;
   ?) days="0"; hms="00:00:0${dhms}"; get_hms "$hms";;
   *) days=""; hms="";;
esac

# strip a leading 0 if any
days="${days#0}"
h="${h#0}"
m="${m#0}"
s="${s#0}"

[ X"$days" = "X" ] && days='0'
[ X"$h" = "X" ] && h='0'
[ X"$m" = "X" ] && m='0'
[ X"$s" = "X" ] && s='0'

printf '%s\n' "d: $days" "h: $h" "m: $m" "s: $s"
days_in_secs=$(( $days * 86400 ))
hours_in_secs=$(( $h * 3600 ))
minutes_in_secs=$(( $m * 60 ))
time_span_in_secs=$(( $days_in_secs + $hours_in_secs + $minutes_in_secs + $s ))
processStartEpochTime="$(( $(date '+%s') - ${time_span_in_secs} ))"
printf '%s\n' "dhms: $dhms"
printf '%s' 'processStartEpochTime reversed: '
date -r "$processStartEpochTime" '+%F--%T'
printf '%s\n' "elapsed seconds: $time_span_in_secs" "elapsed minutes: $(( $time_span_in_secs / 60 ))" "elapsed hours: $(( $time_span_in_secs / 3600 ))"

}