Bash 格式化正常运行时间以显示天、小时、分钟

Bash format uptime to show days, hours, minutes

我在 bash 中使用正常运行时间来获取机器的当前运行时间。我需要抓取时间并显示类似 2 天 12 小时 23 分钟的格式。

我的 uptime 生成如下所示的输出:

$ uptime
 12:49:10 up 25 days, 21:30, 28 users,  load average: 0.50, 0.66, 0.52

要将其转换为您的格式:

$ uptime | awk -F'( |,|:)+' '{print ,",",,"hours,",,"minutes."}'
25 days, 21 hours, 34 minutes.

工作原理

  • -F'( |,|:)+'

    awk 将其输入分成字段。这告诉 awk 使用 space、逗号或冒号中的一个或多个的任意组合作为字段分隔符。

  • print ,",",,"hours,",,"minutes."

    这告诉 awk 打印第六个字段和第七个字段(由 space 分隔)后跟一个逗号,第 8 个字段,字符串 hours, 第九个字段,最后,字符串 minutes..

使用 sed 处理正常运行时间较短的计算机

从重启开始,我的 uptime 产生如下输出:

 03:14:20 up 1 min,  2 users,  load average: 2.28, 1.29, 0.50
 04:12:29 up 59 min,  5 users,  load average: 0.06, 0.08, 0.48
 05:14:09 up  2:01,  5 users,  load average: 0.13, 0.10, 0.45
 03:13:19 up 1 day, 0 min,  8 users,  load average: 0.01, 0.04, 0.05
 04:13:19 up 1 day,  1:00,  8 users,  load average: 0.02, 0.05, 0.21
 12:49:10 up 25 days, 21:30, 28 users,  load average: 0.50, 0.66, 0.52

以下 sed 命令处理这些格式:

uptime | sed -E 's/^[^,]*up *//; s/, *[[:digit:]]* users.*//; s/min/minutes/; s/([[:digit:]]+):0?([[:digit:]]+)/ hours,  minutes/' 

经过以上次数,产生:

1 minutes
59 minutes
2 hours, 1 minutes
1 day, 0 minutes
1 day,  1 hours, 0 minutes
25 days, 21 hours, 30 minutes

工作原理

  • -E 打开扩展正则表达式语法。 (在较旧的 GNU seds 上,使用 -r 代替 -E

  • s/^[^,]*up *//

    此替换命令删除所有文本直至 up

  • s/, *[[:digit:]]* users.*//

    此替换命令删除用户计数及其后的所有文本。

  • s/min/minutes/

    这会将 min 替换为 minutes

  • s/([[:digit:]]+):0?([[:digit:]]+)/ hours, minutes/'

    如果该行包含 hh:mm 格式的时间,这会将小时与分钟分开,并将其替换为 hh hours, mm minutes

使用 awk 处理正常运行时间较短的计算机

uptime | awk -F'( |,|:)+' '{d=h=m=0; if (=="min") m=; else {if (~/^day/) {d=;h=;m=} else {h=;m=}}} {print d+0,"days,",h+0,"hours,",m+0,"minutes."}'

在与上面相同的测试用例中,这会产生:

0 days, 0 hours, 1 minutes.
0 days, 0 hours, 59 minutes.
0 days, 2 hours, 1 minutes.
1 days, 0 hours, 0 minutes.
1 days, 1 hours, 0 minutes.
25 days, 21 hours, 30 minutes.

对于那些喜欢将 awk 代码分散到多行的人:

uptime | awk -F'( |,|:)+' '{
    d=h=m=0;
    if (=="min")
        m=;
    else {
        if (~/^day/) { d=; h=; m=}
        else {h=;m=}
        }
    }
    {
        print d+0,"days,",h+0,"hours,",m+0,"minutes."
    }'

为了多样性,这里有一个使用 sed 的例子:

我的原始输出:

$ uptime
15:44:56 up 3 days, 22:58,  7 users,  load average: 0.48, 0.40, 0.31

转换输出:

$uptime|sed 's/.*\([0-9]\+ days\), \([0-9]\+\):\([0-9]\+\).*/,  hours,  minutes./'
3 days, 22 hours, 58 minutes.

为了完整性...关于:

$ uptime -p
up 2 weeks, 3 days, 14 hours, 27 minutes

这个答案对于 OS X 中的 uptime 非常具体,但考虑到了输出的任何情况。

#!/bin/bash

INFO=`uptime`
echo $INFO | awk -F'[ ,:\t\n]+' '{
        msg = "↑ "
        if ( == "day" ||  == "days") {      # up for a day or more
            msg = msg  " "  ", "

            n = 
            o = 
        } else {
            n = 
            o = 
        }

        if (int(o) == 0) {                      # words evaluate to zero
            msg = msg int(n)" "o
        } else {                                # hh:mm format
            msg = msg int(n)" hr"
            if (n > 1) { msg = msg "s" }

            msg = msg ", " int(o) " min"
            if (o > 1) { msg = msg "s" }
        }

        print "[", msg, "]"
    }'

一些可能的输出示例:

22:49 up 24 secs, 2 users, load averages: 8.37 2.09 0.76
[ ↑ 24 secs ]

22:50 up 1 min, 2 users, load averages: 5.59 2.39 0.95
[ ↑ 1 min ]

23:39 up 51 mins, 3 users, load averages: 2.18 1.94 1.74
[ ↑ 51 mins ]

23:54 up 1:06, 3 users, load averages: 3.67 2.57 2.07
[ ↑ 1 hr, 6 mins ]

16:20 up 120 days, 10:46, 3 users, load averages: 1.21 2.88 0.80
[ ↑ 120 days, 10 hrs, 46 mins ]

为此:

  • 0 天 0 小时 1 分钟。
  • 0 天 0 小时 59 分钟。
  • 0 天 2 小时 1 分钟。
  • 1 天 0 小时 0 分钟。
  • 1 天 1 小时 0 分钟。
  • 25 天 21 小时 30 分钟

更简单的是:
uptime -p | cut -d " " -f2-

我制作了一个通用的 shell 脚本,用于支持 uptime -p 的系统,如更新的 linux 和不支持的系统,如 Mac OS X.

#!/bin/sh

uptime -p >/dev/null 2>&1

if [ "$?" -eq 0 ]; then
  # Supports most Linux distro
  # when the machine is up for less than '0' minutes then
  # 'uptime -p' returns ONLY 'up', so we need to set a default value
  UP_SET_OR_EMPTY=$(uptime -p | awk -F 'up ' '{print }')
  UP=${UP_SET_OR_EMPTY:-'less than a minute'}
else
  # Supports Mac OS X, Debian 7, etc
  UP=$(uptime | sed -E 's/^[^,]*up *//; s/mins/minutes/; s/hrs?/hours/;
  s/([[:digit:]]+):0?([[:digit:]]+)/ hours,  minutes/;
  s/^1 hours/1 hour/; s/ 1 hours/ 1 hour/;
  s/min,/minutes,/; s/ 0 minutes,/ less than a minute,/; s/ 1 minutes/ 1 minute/;
  s/  / /; s/, *[[:digit:]]* users?.*//')
fi

echo "up $UP"

Gist

参考了 John1024 的回答,自己定制。

uptime_minutes() {
  set `uptime -p`
  local minutes=0

  shift
  while [ -n "" ]; do
    case  in
      day*)
        ((minutes+=*1440))
        ;;
      hour*)
        ((minutes+=*60))
        ;;
      minute*)
        ((minutes+=))
        ;;
    esac
   shift
   shift
  done

  echo $minutes
}

解决方案:为了以秒为单位获得 linux 正常运行时间,转到 bash 并键入 cat /proc/uptime。解析第一个数字并根据您的要求进行转换。

来自 RedHat documentation:

This file contains information detailing how long the system has been on since its last restart. The output of /proc/uptime is quite minimal:

350735.47 234388.90

The First number is the total number of seconds the system has been up.

The Second number is how much of that time the machine has spent idle, in seconds.