19

I'm using uptime in bash in order to get the current runtime of the machine. I need to grab the time and display a format like 2 days, 12 hours, 23 minutes.

user1799031
  • 213
  • 1
  • 2
  • 7

8 Answers8

41

My uptime produces output that looks like:

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

To convert that to your format:

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

How it works

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

    awk divides its input up into fields. This tells awk to use any combination of one or more of space, comma, or colon as the field separator.

  • print $6,$7",",$8,"hours,",$9,"minutes."

    This tells awk to print the sixth field and seventh fields (separated by a space) followed by a comma, the 8th field, the string hours, the ninth field, and, lastly, the string minutes..

Handling computers with short uptimes using sed

Starting from a reboot, my uptime produces output like:

 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

The following sed command handles these formats:

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

With the above times, this produces:

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

How it works

  • -E turns on extended regular expression syntax. (On older GNU seds, use -r in place of -E)

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

    This substitutes command removes all text up to up.

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

    This substitute command removes the user count and all text which follows it.

  • s/min/minutes/

    This replaces min with minutes.

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

    If the line contains a time in the hh:mm format, this separates the hours from the minutes and replaces it with hh hours, mm minutes.

Handling computers with short uptimes using awk

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

On the same test cases as above, this produces:

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.

For those who prefer awk code spread out over multiple lines:

uptime | awk -F'( |,|:)+' '{
    d=h=m=0;
    if ($7=="min")
        m=$6;
    else {
        if ($7~/^day/) { d=$6; h=$8; m=$9}
        else {h=$6;m=$7}
        }
    }
    {
        print d+0,"days,",h+0,"hours,",m+0,"minutes."
    }'
John1024
  • 109,961
  • 14
  • 137
  • 171
  • 1
    Thanks for the awk solution. One small improvement when piping a file with several uptimes into it, I needed to reset the variables: `cat filewithuptimes.log | awk -F'( |,|:)+' 'd=0; h=0; m=0; {if ($7=="min") m=$6; else {if ($7~/^day/) {d=$6;h=$8;m=$9} else {h=$6;m=$7}}} {print d+0,"days,",h+0,"hours,",m+0,"minutes."}'` – mrvulcan Jun 05 '19 at 22:22
  • @mrvulcan Good observation! I just updated the answer to initialize those variables so that the case of multiple input lines is handled. Thanks. – John1024 Jun 05 '19 at 23:03
29

Just vor completeness... what's about:

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

Solution: In order to get the linux uptime in seconds, Go to bash and type cat /proc/uptime.Parse the first number and convert it according to your requirement.

From 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.

avivamg
  • 12,197
  • 3
  • 67
  • 61
3

I made a universal shell script, for systems which support uptime -p like newer linux and for those that don't, like 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 $2}')
  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:]]+)/\1 hours, \2 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

Referenced John1024 answer with my own customizations.

flou
  • 41
  • 1
  • 3
2

For this:

  • 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

More simple is:
uptime -p | cut -d " " -f2-

Sofya
  • 29
  • 1
  • this doesn’t print anything like “0 days”, at least not with uptime from procps-ng 3.3.16. – dessert Dec 18 '20 at 07:47
1

For the sake of variety, here's an example with sed:

My raw output:

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

Converted output:

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

This answer is pretty specific for the uptime shipped in OS X, but takes into account any case of output.

#!/bin/bash

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

            n = $6
            o = $7
        } else {
            n = $4
            o = $5
        }

        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, "]"
    }'

Some example possible outputs:

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 ]
chamini2
  • 2,820
  • 2
  • 24
  • 37
0
uptime_minutes() {
  set `uptime -p`
  local minutes=0

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

  echo $minutes
}